BRIC Project

# clear workspace
##rm(list=ls())

getting the current WD

getwd()

0.1 Loading Libraries

# loading libraries
library(data.table) # extension of the data.frame package. It is widely used for fast aggregation of large datasets, low latency add/update/remove of columns, quicker ordered joins, and a fast file reader.
library(dplyr) # data manipulation package
library(lubridate)
library(zoo) # methods for totally ordered indexed observations. It aims at performing calculations containing irregular time series of numeric vectors, matrices & factors
library(stats)
library(utils)
library(tidyverse)
library(readr)
library(ggplot2)
library(reshape2)

0.2 Loading in the R.data

Data column descriptions (Worldscope): https://www.professors.wi.tum.de/fileadmin/w00bca/fm/Worldscope_Data_Definition_Guide_Issue_15.pdf

https://docs.google.com/spreadsheets/d/1YtuJiv60Q6nKIaFJLQY60sGQErbsl_8nvPdUHmvO8vM/edit?usp=sharing

0.2.1 Loading data Johannes

memory.limit(9999999999)
[1] 1e+10
# loading R.data BRIC monthly
load("C:/Users/johan/Documents/BRIC_Asset_Pricing_Project/BRIC_monthly.RData")

# loading R.data BRIC static
load("C:/Users/johan/Documents/BRIC_Asset_Pricing_Project/BRIC_static.RData")
strings not representable in native encoding will be translated to UTF-8input string 'NIZHNY NOVGOROD AIRCRAFT BUILDING PLANT愼㸰 OJSC' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'CHINA愼㸰DIGITAL愼㸰TV愼㸰HOLDING' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'CRAZY愼㸰INFOTECH愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'KILITCH愼㸰DRUGS愼㸰(INDIA)愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'SHIRPUR愼㸰GOLD愼㸰REFINERY' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'WINSOME TEXTILE愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'PLETHICO PHARMACEUTICALS愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'RAP MEDIA愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'RICOH愼㸰INDIA' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'MTZ愼㸰POLYFILMS' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'BASANT AGRO TECH (INDIA)愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'NAGPUR POWER & INDS 愼㸰' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'PAREKH愼㸰ALUMINEX' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'OMNITECH愼㸰INFOSOLUTIONS' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'MAYUR愼㸰LEATHER愼㸰PRODUCTS' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'SPARSH愼㸰BPO SVERVICES LTD' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string 'CAMLIN愼㸰FINE愼㸰CHEMICALS愼㸰 LIMITED' cannot be translated to UTF-8, is it valid in 'UTF-8' ?input string '愼㸰TOMSK TNSM.GRIDS' cannot be translated to UTF-8, is it valid in 'UTF-8' ?
# loading R.data BRIC yearly
load("C:/Users/johan/Documents/BRIC_Asset_Pricing_Project/BRIC_yearly.RData")

0.2.2 Loading data Manuel

# loading R.data BRIC monthly
load("/Users/Manu/Desktop/TUM_Master_Mgt_Technology/TUM_SS_21/Empirical Asset Pricing seminar/Seminar Thesis/BRIC_data/BRIC_monthly.RData")
# loading R.data BRIC monthly
load("/Users/Manu/Desktop/TUM_Master_Mgt_Technology/TUM_SS_21/Empirical Asset Pricing seminar/Seminar Thesis/BRIC_data/BRIC_static.RData")
# loading R.data BRIC monthly
load("/Users/Manu/Desktop/TUM_Master_Mgt_Technology/TUM_SS_21/Empirical Asset Pricing seminar/Seminar Thesis/BRIC_data/BRIC_yearly.RData")

0.2.3 Loading data Vinit

# loading R.data BRIC monthly
load("/Users/vinitkumar/Desktop/SS2021/Cases in Finance/BRIC_Asset_Pricing_Project/BRIC_Data/BRIC_monthly.RData")

# loading R.data BRIC monthly
load("/Users/vinitkumar/Desktop/SS2021/Cases in Finance/BRIC_Asset_Pricing_Project/BRIC_Data/BRIC_static.RData")

# loading R.data BRIC monthly
load("/Users/vinitkumar/Desktop/SS2021/Cases in Finance/BRIC_Asset_Pricing_Project/BRIC_Data/BRIC_yearly.RData")

0.2.4 Loading data Chandra

# loading R.data BRIC monthly
load("/Users/cg/Desktop/TUM/SS21/Empirical Asset Pricing Seminar/Presentation/BRIC_Data/BRIC_monthly.RData")

# loading R.data BRIC yearly
load("/Users/cg/Desktop/TUM/SS21/Empirical Asset Pricing Seminar/Presentation/BRIC_Data/BRIC_yearly.RData")

# loading R.data BRIC static
load("/Users/cg/Desktop/TUM/SS21/Empirical Asset Pricing Seminar/Presentation/BRIC_Data/BRIC_static.RData")

Data preparation

1 Save raw data and adjust date range

#0 save raw data
BRIC.monthly.raw <- BRIC.monthly
BRIC.yearly.raw <- BRIC.yearly

#1 adjust date range (from July 1994 to December 2018)
#1.1 leave raw data with date adjustment
BRIC.monthly.withNA <- subset(BRIC.monthly.raw, Date >= "1994-06-30" & Date <= "2019-02-01")
BRIC.yearly.withNA <- subset(BRIC.yearly.raw, YEAR >= "1994" & YEAR <= "2019")
#1.2 working dataframe
BRIC.monthly <- subset(BRIC.monthly, Date >= "1994-06-30" & Date <= "2019-02-01")
BRIC.yearly <- subset(BRIC.yearly, YEAR >= "1994" & YEAR <= "2019")

2 BRIC.monthly data preparation

at this point of time the data sheet is still balanced, therefore we can use the shift function

# add a new column for the lagged MV.USD (this is the MV.USD from the previous month) 
BRIC.monthly[, LMV.USD := lag((MV.USD),1), by =Id]

# add a new column for volatility
BRIC.monthly[, volatility := lag(rollapplyr(RET.USD, 36, sd, fill = NA, partial = 12),1), by =Id]

# add 12 new columns for last 12 months returns
BRIC.monthly[, lag1 := lag((RET.USD),1), by =Id]
BRIC.monthly[, lag2 := lag((RET.USD),2), by =Id]
BRIC.monthly[, lag3 := lag((RET.USD),3), by =Id]
BRIC.monthly[, lag4 := lag((RET.USD),4), by =Id]
BRIC.monthly[, lag5 := lag((RET.USD),5), by =Id]
BRIC.monthly[, lag6 := lag((RET.USD),6), by =Id]
BRIC.monthly[, lag7 := lag((RET.USD),7), by =Id]
BRIC.monthly[, lag8 := lag((RET.USD),8), by =Id]
BRIC.monthly[, lag9 := lag((RET.USD),9), by =Id]
BRIC.monthly[, lag10 := lag((RET.USD),10), by =Id]
BRIC.monthly[, lag11 := lag((RET.USD),11), by =Id]
BRIC.monthly[, lag12 := lag((RET.USD),12), by =Id]

typeof(BRIC.monthly$lag1)
[1] "double"
# negative values are replaced to 0
#ifelse(BRIC.monthly$lag1<=0,0,ifelse(BRIC.monthly$lag1>0,1,NA))
BRIC.monthly$lag1 <- replace(BRIC.monthly$lag1,BRIC.monthly$lag1<=0,0)
BRIC.monthly$lag2 <- replace(BRIC.monthly$lag2,BRIC.monthly$lag2<=0,0)
BRIC.monthly$lag3 <- replace(BRIC.monthly$lag3,BRIC.monthly$lag3<=0,0)
BRIC.monthly$lag4 <- replace(BRIC.monthly$lag4,BRIC.monthly$lag4<=0,0)
BRIC.monthly$lag5 <- replace(BRIC.monthly$lag5,BRIC.monthly$lag5<=0,0)
BRIC.monthly$lag6 <- replace(BRIC.monthly$lag6,BRIC.monthly$lag6<=0,0)
BRIC.monthly$lag7 <- replace(BRIC.monthly$lag7,BRIC.monthly$lag7<=0,0)
BRIC.monthly$lag8 <- replace(BRIC.monthly$lag8,BRIC.monthly$lag8<=0,0)
BRIC.monthly$lag9 <- replace(BRIC.monthly$lag9,BRIC.monthly$lag9<=0,0)
BRIC.monthly$lag10 <- replace(BRIC.monthly$lag10,BRIC.monthly$lag10<=0,0)
BRIC.monthly$lag11 <- replace(BRIC.monthly$lag11,BRIC.monthly$lag11<=0,0)
BRIC.monthly$lag12 <- replace(BRIC.monthly$lag12,BRIC.monthly$lag12<=0,0)

# positive values are replaced to 1
BRIC.monthly$lag1 <- replace(BRIC.monthly$lag1,BRIC.monthly$lag1>0,1)
BRIC.monthly$lag2 <- replace(BRIC.monthly$lag2,BRIC.monthly$lag2>0,1)
BRIC.monthly$lag3 <- replace(BRIC.monthly$lag3,BRIC.monthly$lag3>0,1)
BRIC.monthly$lag4 <- replace(BRIC.monthly$lag4,BRIC.monthly$lag4>0,1)
BRIC.monthly$lag5 <- replace(BRIC.monthly$lag5,BRIC.monthly$lag5>0,1)
BRIC.monthly$lag6 <- replace(BRIC.monthly$lag6,BRIC.monthly$lag6>0,1)
BRIC.monthly$lag7 <- replace(BRIC.monthly$lag7,BRIC.monthly$lag7>0,1)
BRIC.monthly$lag8 <- replace(BRIC.monthly$lag8,BRIC.monthly$lag8>0,1)
BRIC.monthly$lag9 <- replace(BRIC.monthly$lag9,BRIC.monthly$lag9>0,1)
BRIC.monthly$lag10 <- replace(BRIC.monthly$lag10,BRIC.monthly$lag10>0,1)
BRIC.monthly$lag11 <- replace(BRIC.monthly$lag11,BRIC.monthly$lag11>0,1)
BRIC.monthly$lag12 <- replace(BRIC.monthly$lag12,BRIC.monthly$lag12>0,1)

BRIC.monthly$lagSum <- BRIC.monthly$lag1 + BRIC.monthly$lag2 + BRIC.monthly$lag3 + BRIC.monthly$lag4 + BRIC.monthly$lag5 + BRIC.monthly$lag6 + BRIC.monthly$lag7 + BRIC.monthly$lag8 + BRIC.monthly$lag9 + BRIC.monthly$lag10 + BRIC.monthly$lag11 + + BRIC.monthly$lag12

BRIC.monthly[ , pf.momentum := ifelse(lagSum>=8,"Winner",ifelse(lagSum < 8,"Looser",NA))]

# delete all entrys before July 1994
BRIC.monthly <- subset(BRIC.monthly, Date >= "1994-07-29" & Date <= "2019-02-01")

# calculate MV.USD.June for every column
# help columns
BRIC.monthly[,month := month(Date)]
BRIC.monthly[,year := year(Date)]
BRIC.monthly[,hcjun := ifelse(month>=7,year,year-1)]
# MV.USD.June column
intermediate <- filter(BRIC.monthly,BRIC.monthly$month == 7)
# minimise for join
intermediate <- subset(intermediate, select = c("Id","LMV.USD","hcjun"))
colnames(intermediate)[2] <- "MV.USD.June"
BRIC.monthly <- subset(BRIC.monthly, select = c("Id","country","Date","MV","MV.USD","LMV.USD","RET","RET.USD","volatility","pf.momentum","ym","hcjun","year","month"))

# inner join automatically deletes values where MV.USD.June is not available
BRIC.monthly <- inner_join(x = BRIC.monthly,y = intermediate, by = c("Id","hcjun"))
# order BRIC.monthly
BRIC.monthly <- subset(BRIC.monthly, select = c("Id","country","Date","MV","MV.USD","LMV.USD","MV.USD.June","RET","RET.USD","volatility","pf.momentum","ym","hcjun","year","month"))

# scale
BRIC.monthly$MV <- BRIC.monthly$MV * 1000000
BRIC.monthly$MV.USD <- BRIC.monthly$MV.USD * 1000000

2.1 Raw code to remove NAs (BRIC.monthly)

# delete na's, set 0 and calculate important values
# no RET.USD data, no MV or no LMV.USD
BRIC.monthly <- BRIC.monthly %>%
  drop_na(RET.USD,MV,MV.USD,LMV.USD,MV.USD.June,volatility,pf.momentum)

3 BRIC.yearly data preparation and value calculation

#3.0 the BRIC.yearly panel here is still balanced! We need to add a column for total assets the year before ----
#add the lagged WC03501 (shifted by Id) (this is the WC03501 from the previous month) 
BRIC.yearly[, lag.value:=c(0, WC03501[-.N]), by=Id] 
# rename column to LMV.USD
colnames(BRIC.yearly)[106] <- "TotalAssetsBefore"

#3.1 book value / equity and related ----
# delete rows with no WC03501 (Common equity)
BRIC.yearly <- BRIC.yearly %>%
  drop_na(WC03501)
# set WC03263 (deferred taxes) zero if NA
BRIC.yearly$WC03263 <- BRIC.yearly$WC03263 %>% replace_na(0)
# add column for BookValue (Hanauer 2020 calculation)
BRIC.yearly$BookValue <- BRIC.yearly$WC03501 + BRIC.yearly$WC03263
# delete rows with negative BookValue
BRIC.yearly <- BRIC.yearly[BRIC.yearly$BookValue >= 0,]

#3.2 total assets ----
# delete rows with no WC02999 (total assets)
BRIC.yearly <- BRIC.yearly %>%
  drop_na(WC02999)
# delete rows with no TotalAssetsBefore
BRIC.yearly <- BRIC.yearly %>%
  drop_na(TotalAssetsBefore)

#3.3 operating profits ----
# "To have a valid value, at least one of cost components cost of goods sold, selling, general and administrative expenses, or interest expense must be non-missing." (Hanauer, 2019, p. 284) --> if one of these values is missing, we must delete these rows WC01001,WC01051,WC01101,WC01251
# delete rows where ALL 4 columns are NA
BRIC.yearly <- filter(BRIC.yearly,!is.na(WC01001) | !is.na(WC01051) | !is.na(WC01101) | !is.na(WC01251))
# replace all na's in this 4 columns with 0
BRIC.yearly$WC01001 <- BRIC.yearly$WC01001 %>% replace_na(0)
BRIC.yearly$WC01051 <- BRIC.yearly$WC01051 %>% replace_na(0)
BRIC.yearly$WC01101 <- BRIC.yearly$WC01101 %>% replace_na(0)
BRIC.yearly$WC01251 <- BRIC.yearly$WC01251 %>% replace_na(0)
# calculate operating profits (Hanauer, 2019, p.284)
BRIC.yearly$OperatingProfits <- (BRIC.yearly$WC01001 - BRIC.yearly$WC01051 - BRIC.yearly$WC01101 - BRIC.yearly$WC01251)

# 3.4 minimise data frame ----
# for BRIC.yearly we keep: Id, country, ICBSUC, YEAR, BookValue, OperatingProfits and total assets
# Note: WC07201 is not used, as our MV should be the MV from the monthly data for 06.y !
BRIC.yearly <- subset(BRIC.yearly, select = c("Id","country","ICBSUC","YEAR","BookValue","OperatingProfits","WC02999","TotalAssetsBefore"))
# we rename WC02999 to total assets
colnames(BRIC.yearly)[7] <- "TotalAssets"

# 3.5 create a help column hcdec (1 year lag) ----
BRIC.yearly$hcdec <- BRIC.yearly$YEAR + 1

# scale
BRIC.yearly$BookValue <- BRIC.yearly$BookValue *1000
BRIC.yearly$OperatingProfits <- BRIC.yearly$OperatingProfits *1000
BRIC.yearly$WC02999 <- BRIC.yearly$WC02999 *1000
BRIC.yearly$TotalAssetsBefore <- BRIC.yearly$TotalAssetsBefore *1000

4 FF5FM Calculation

4.1 Adding the 1-m treasury rate to the monthly data

# load data sheet from French's website
FFData <- read_csv("FF_Research_Data_5_Factors_2x3.CSV", 
     skip = 2)
# shorting data frame
one_m_tbill <- as.data.frame(FFData[c("X1","RF")][1:693,])
# adding a ym column to risk free rate data
one_m_tbill$ym<-as.yearmon(one_m_tbill$X1, "%Y %m")
#delete X1 column 
one_m_tbill <- subset(one_m_tbill,select = c("ym","RF"))
# merge risk-free rate (1 month treasury bill rate) with monthly data
BRIC.monthly <- left_join(x = BRIC.monthly, y = one_m_tbill, by = "ym")

# make rf column numeric
BRIC.monthly$RF <- as.numeric(BRIC.monthly$RF)

# Add RiRF ----
BRIC.monthly$RiRF <- BRIC.monthly$RET.USD - BRIC.monthly$RF
# Local currency RiRF
BRIC.monthly$RiRF.local <- BRIC.monthly$RET - BRIC.monthly$RF

4.2 Merge monthly and accounting (yearly) data

NOTE: Here we “loose” around 600 000 rows!

BRIC.maindata <- inner_join(x = BRIC.monthly,y = BRIC.yearly, by = c("Id","hcjun" = "hcdec"))

# Add a B/M column
BRIC.maindata$BM <- BRIC.maindata$BookValue / BRIC.maindata$MV
# Add a OP/BE column
BRIC.maindata$OPBE <- BRIC.maindata$OperatingProfits / BRIC.maindata$BookValue
# Add a AssetChange column
BRIC.maindata$AssetChange <- ((BRIC.maindata$TotalAssets - BRIC.maindata$TotalAssetsBefore)/BRIC.maindata$TotalAssetsBefore)

BRIC.maindata <- subset(BRIC.maindata, hcjun >= "1996")

BREAKPOINT

If we want to calculate factors or anything else for countries standalone we will have to filter them here! For multiple trys run 4.2 again, to reset BRIC.maindata

# e.g. filter for China
##BRIC.maindata <- filter(BRIC.maindata,BRIC.maindata$country.x == "CHN")

4.3 SMB: Determine size Breakpoints

setorder(BRIC.maindata,Date,-MV.USD.June)
hlpvariable <-  BRIC.maindata[month==7 & !is.na(MV.USD.June),
                .(pf.size = ifelse((cumsum(MV.USD.June)/sum(MV.USD.June))>=0.9,"Small","Big"),Id),
                               by=year]

# Merge the size portfolio allocation back from July Y to June Y+1
BRIC.maindata <- merge(BRIC.maindata,hlpvariable,
                       by.x=c("hcjun","Id"),
                       by.y=c("year","Id"),
                       all.x=T)

# delete NA's (only about 1000 rows)
BRIC.maindata <- na.omit(BRIC.maindata,cols = "pf.size") 

RiRF used for benchmark in p.50 lecture slides For annualisation we used arithmetic average * 12

4.4 Benchmark (Value weighted)

# create copy
BRIC.benchmark <- BRIC.maindata

# filter on pf.size
BRIC.benchmark <- subset(BRIC.benchmark, pf.size == "Big" )

# value weight returns
## calculate monthly market value over all stocks
BRIC.benchmark.valueWeights <- aggregate(LMV.USD ~ ym, data = BRIC.benchmark, FUN = sum)
colnames(BRIC.benchmark.valueWeights)[2] <- "TotalValue"

## join value weights to stocks
BRIC.benchmark <- inner_join(x = BRIC.benchmark, y = BRIC.benchmark.valueWeights, by = "ym")

## calculate value weight
BRIC.benchmark$ValueWeight <- BRIC.benchmark$LMV.USD/BRIC.benchmark$TotalValue

## calculate value weight excess return / return
BRIC.benchmark$wRet <- BRIC.benchmark$ValueWeight*BRIC.benchmark$RET.USD
BRIC.benchmark$wExRet <- BRIC.benchmark$ValueWeight * BRIC.benchmark$RiRF

# per month
benchmark.retBricM <- aggregate(cbind(wRet,wExRet) ~ ym + hcjun, data = BRIC.benchmark,FUN = sum)

# per year
benchmark.retBricY <- aggregate(cbind(wRet,wExRet) ~ hcjun, data = benchmark.retBricM,FUN = mean)

## annualise
benchmark.retBricY$wRet <- benchmark.retBricY$wRet*12
benchmark.retBricY$wExRet <- benchmark.retBricY$wExRet*12

# per country
benchmark.retCountryM <- aggregate(cbind(wRet,wExRet) ~ country.x + ym + hcjun, data = BRIC.benchmark,FUN = sum)

# per year
benchmark.retCountryY <- aggregate(cbind(wRet,wExRet) ~ country.x + hcjun, data = benchmark.retCountryM,FUN = mean)

## annualise
benchmark.retCountryY$wRet <- benchmark.retCountryY$wRet*12
benchmark.retCountryY$wExRet <- benchmark.retCountryY$wExRet*12

# single dataframe
benchmark_BRIC <- inner_join(benchmark.retBricY,benchmark.retBricM,by = "hcjun")
benchmark_Country <- inner_join(benchmark.retCountryY,benchmark.retCountryM,by = c("hcjun","country.x"))
# rename columns
colnames(benchmark_BRIC)[2] <- "YearlyReturn"
colnames(benchmark_BRIC)[3] <- "YearlyExcessReturn"
colnames(benchmark_BRIC)[5] <- "MonthlyReturn"
colnames(benchmark_BRIC)[6] <- "MonthlyExcessReturn"

colnames(benchmark_Country)[3] <- "YearlyReturn"
colnames(benchmark_Country)[4] <- "YearlyExcessReturn"
colnames(benchmark_Country)[6] <- "MonthlyReturn"
colnames(benchmark_Country)[7] <- "MonthlyExcessReturn"

4.5 Market (Excess) Return

# create copy
BRIC.market <- BRIC.maindata

# value weight returns
## calculate monthly market value over all stocks
BRIC.market.valueWeights <- aggregate(LMV.USD ~ ym, data = BRIC.market, FUN = sum)
colnames(BRIC.market.valueWeights)[2] <- "TotalValue"

## join value weights to stocks
BRIC.market <- inner_join(x = BRIC.market, y = BRIC.market.valueWeights, by = "ym")

## calculate value weight
BRIC.market$ValueWeight <- BRIC.market$LMV.USD/BRIC.market$TotalValue

## calculate value weight excess return / return
BRIC.market$wRet <- BRIC.market$ValueWeight*BRIC.market$RET.USD
BRIC.market$wExRet <- BRIC.market$ValueWeight * BRIC.market$RiRF

# per month
market.retBricM <- aggregate(cbind(wRet,wExRet) ~ ym + hcjun, data = BRIC.market,FUN = sum)

# per year
market.retBricY <- aggregate(cbind(wRet,wExRet) ~ hcjun, data = market.retBricM,FUN = mean)

## annualise
market.retBricY$wRet <- market.retBricY$wRet*12
market.retBricY$wExRet <- market.retBricY$wExRet*12

# per country
market.retCountryM <- aggregate(cbind(wRet,wExRet) ~ country.x + ym + hcjun, data = BRIC.market,FUN = sum)

# per year
market.retCountryY <- aggregate(cbind(wRet,wExRet) ~ country.x + hcjun, data = market.retCountryM,FUN = mean)

## annualise
market.retCountryY$wRet <- market.retCountryY$wRet*12
market.retCountryY$wExRet <- market.retCountryY$wExRet*12

# single dataframe
market_BRIC <- inner_join(market.retBricY,market.retBricM,by = "hcjun")
market_Country <- inner_join(market.retCountryY,market.retCountryM,by = c("hcjun","country.x"))
# rename columns
colnames(market_BRIC)[2] <- "YearlyReturn"
colnames(market_BRIC)[3] <- "YearlyExcessReturn"
colnames(market_BRIC)[5] <- "MonthlyReturn"
colnames(market_BRIC)[6] <- "MonthlyExcessReturn"

colnames(market_Country)[3] <- "YearlyReturn"
colnames(market_Country)[4] <- "YearlyExcessReturn"
colnames(market_Country)[6] <- "MonthlyReturn"
colnames(market_Country)[7] <- "MonthlyExcessReturn"

Breakpoints for RMW and CMA are based on Jiao(2017) and FF(2015) 2x3 sort = NYSE Percentiles (FF(2015) p.6) [PortfolioSorts.] (“Images/PortfolioSorts.jpg”) ## 4.6 - 4.8 Determine other breakpoints


# 4.6 HML: Determine B/M breakpoints ----

# Breakpoints for RMW and CMA are based on Jiao(2017) and FF(2015) 2x3 sort = NYSE Percentiles (FF(2015) p.6)
#![PortfolioSorts.] ("Images/PortfolioSorts.jpg")

# Determine the B/M breakpoints based on big stocks only
hlpvariable2 <- BRIC.maindata[month==7 & !is.na(BM) & pf.size=="Big", .(bm_bb30 = quantile(BM , probs = c(0.3), na.rm=T),
                                                                        bm_bb70 = quantile(BM , probs = c(0.7), na.rm=T)),by=year]
              
# Merge the B/M portfolio allocation back from July Y to June Y+1
BRIC.maindata <- merge(BRIC.maindata,hlpvariable2,
                       by.x=c("hcjun"),
                       by.y=c("year"),
                       all.x=T)

BRIC.maindata[ , pf.bm := ifelse(BM>bm_bb70,"High",ifelse((BM<=bm_bb70 & BM>bm_bb30),"Neutral",ifelse(BM<=bm_bb30,"Low",NA)))]

BRIC.maindata[, SIZE_VALUE := paste0(pf.size,".",pf.bm)]

# 4.7 RMW: Determine OP/BE breakpoints ----

# Determine the OP/BE breakpoints based on big stocks only
hlpvariable2 <- BRIC.maindata[month==7 & !is.na(OPBE) & pf.size=="Big", .(opbe_bb30 = quantile(OPBE , probs = c(0.3), na.rm=T),
                                                                        opbe_bb70 = quantile(OPBE , probs = c(0.7), na.rm=T)),by=year]
              
# Merge the OP/BE portfolio allocation back from July Y to June Y+1
BRIC.maindata <- merge(BRIC.maindata,hlpvariable2,
                       by.x=c("hcjun"),
                       by.y=c("year"),
                       all.x=T)

# 3 OP/BE brackets: Robust, Neutral and Weak
BRIC.maindata[ , pf.opbe := ifelse(OPBE>opbe_bb70,"Robust",ifelse((OPBE<=opbe_bb70 & OPBE>opbe_bb30),"Neutral",ifelse(OPBE<=opbe_bb30,"Weak",NA)))]

BRIC.maindata[, SIZE_PROFITABILITY := paste0(pf.size,".",pf.opbe)]

# 4.8 CMA: Determine Asset Change Breakpoints ----

#investment: As in Cooper et al. (2008), we measure asset growth in June of year y as the percentage change in total assets (WC02999) from fiscal year ending in calendar year y−2 to fiscal year ending in calendar year y−1.

# Determine the AC breakpoints based on big stocks only
hlpvariable2 <- BRIC.maindata[month==7 & !is.na(AssetChange) & pf.size=="Big", .(ac_bb30 = quantile(AssetChange , probs = c(0.3), na.rm=T),
                                                                        ac_bb70 = quantile(AssetChange , probs = c(0.7), na.rm=T)),by=year]
              
# Merge the AC portfolio allocation back from July Y to June Y+1
BRIC.maindata <- merge(BRIC.maindata,hlpvariable2,
                       by.x=c("hcjun"),
                       by.y=c("year"),
                       all.x=T)

# 3 investment brackets: Aggressive, neutral and conservative
BRIC.maindata[ , pf.ac := ifelse(AssetChange>ac_bb70,"Aggressive",ifelse((AssetChange<=ac_bb70 & AssetChange>ac_bb30),"Neutral",ifelse(AssetChange<=ac_bb30,"Conservative",NA)))]

BRIC.maindata[, SIZE_INVESTMENT := paste0(pf.size,".",pf.ac)]

https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/Data_Library/f-f_5_factors_2x3.html

##4.9 Calculate Factors

summary(BRIC.maindata$BM)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
  0.0000   0.2215   0.4452   1.5640   1.0005 724.0493 

ISIN: International Security Identification Number (stock identifier) ESTAT: active vs inactive company (publicly listed or not) Id: join column with BRIC.yearly dataframe INDM: industry sector code

GEOGN: geographic group name GEOLN: geographic location

List of Database codes: https://www.bwl.uni-mannheim.de/media/Lehrstuehle/bwl/Maug/Database_info/Datastream_dataypes.pdf

ID: ?? Country: 4 BRIC COUNTRY CODES ICBSUC: industrial classification benchmark https://link.springer.com/content/pdf/bbm%3A978-3-8350-9531-1%2F1.pdf

WC07021: SIC(standard industrial classification) primary code from Worldscope W05651: Common Shares Traded - Annual (Security)

TO DO’s:

  • Calculate Benchmark (market-cap weighted big stocks of the BRIC region) || DONE
  • Calculate break points on big stocks || DONE
  • decide on strategy and implement it || WORKING
  • calculate portfolio characteristics
  • visualize and showcase strategy performance
  • regress strategy PF on FF5FM and momentum for style exposure analysis
  • Literature || WIP
  • sorting A-shares … how to identify them? || DONE

Project Dates: Thesis submission: June 21 Final presentation: June 07

Strategy: GDP weighted countries; stock level: max sharpe ratio, min volatility, equal sector weights or quotas, momentum?

EDA

To DO: compute correlations by sector (10 sectors)

# regular correlation matrix of all (four) numeric attributes
cor(select(BRIC.static, where(is.numeric)))

Some conventions:

Characteristic should be calculated as in Hanauer & Lauterbach (2019) or in Hanauer (2020)

Big stocks should be defined as the biggest stocks which together account for 90% of a country’s aggregated market capitalization Benchmark should be defined as the cap-weighted universe of big stocks Returns should be in USD Breakpoints (for Fama-French factors) should be calculated on big stocks (as in the excursus) but both small and big stocks go into the factor calculation.

#5.STRATEGY - Multifactor Portfolio sort Momentum sorting is done during #2. ##5.1 Value Breakpoints

BRIC.strategy <- BRIC.maindata

colnames(BRIC.strategy)
 [1] "hcjun"              "Id"                 "country.x"          "Date"               "MV"                 "MV.USD"            
 [7] "LMV.USD"            "MV.USD.June"        "RET"                "RET.USD"            "volatility"         "pf.momentum"       
[13] "ym"                 "year"               "month"              "RF"                 "RiRF"               "RiRF.local"        
[19] "country.y"          "ICBSUC"             "YEAR"               "BookValue"          "OperatingProfits"   "TotalAssets"       
[25] "TotalAssetsBefore"  "WC02999"            "BM"                 "OPBE"               "AssetChange"        "pf.size"           
[31] "bm_bb30"            "bm_bb70"            "pf.bm"              "SIZE_VALUE"         "opbe_bb30"          "opbe_bb70"         
[37] "pf.opbe"            "SIZE_PROFITABILITY" "ac_bb30"            "ac_bb70"            "pf.ac"              "SIZE_INVESTMENT"   
## Value factor
## creating a large cap and high B/M ratio column (large cap value)

# subsetting the large cap stocks only (rebalanced yearly)
BRIC.strategy <- subset(BRIC.strategy, pf.size == "Big" )

# subsetting only value stocks (cutoff = median) Look up CUTOFF details
# Determine the value breakpoints
hlpvariable2 <- BRIC.maindata[month==7, .(median = quantile(BM , probs = c(0.5), na.rm=T)),by=year]
              
# Merge the value portfolio allocation back from July Y to June Y+1
BRIC.strategy <- merge(BRIC.strategy,hlpvariable2,
                       by.x=c("hcjun"),
                       by.y=c("year"),
                       all.x=T)

BRIC.strategy[ , pf.value := ifelse(BM>median,"Value",(ifelse(BM<=median,"Growth",NA)))]

table(BRIC.strategy$pf.value)

Growth  Value 
148039  74405 
dim(BRIC.strategy)
[1] 222444     44

##5.2 Low Vol Strategy implementation on the balanced panel data (Multifactor etf)


# Determine the low_vol breakpoints based on big stocks only
hlpvariable2 <- BRIC.strategy[month==7, .(lower_20 = quantile(volatility , probs = c(0.2), na.rm=T)),by=year]
              
# Merge the low_vol portfolio allocation back from July Y to June Y+1
BRIC.strategy <- merge(BRIC.strategy,hlpvariable2,
                       by.x=c("hcjun"),
                       by.y=c("year"),
                       all.x=T)

BRIC.strategy[ , pf.low_vol := ifelse(volatility>lower_20,"HighVol",(ifelse(volatility<=lower_20,"LowVol",NA)))]

table(BRIC.strategy$pf.low_vol)

HighVol  LowVol 
 175127   47317 
dim(BRIC.strategy)
[1] 222444     46

##5.3 Filtering for strategy requirements

# filtering for growth stocks
BRIC.strategy <- subset(BRIC.strategy, pf.value == "Growth" )

# filtering for lowVol stocks
BRIC.strategy <- subset(BRIC.strategy, pf.low_vol == "LowVol" )

# filtering for winner stocks
BRIC.strategy <- subset(BRIC.strategy, pf.momentum  == "Winner" )

dim(BRIC.strategy)

summary(BRIC.strategy)

5.4 Statistics on Strategy portfolio

strat.EqualWeights <- aggregate(Id ~ ym, data = BRIC.strategy, FUN=function(x) length(unique(x)))
colnames(strat.EqualWeights)[2] <- "NumberOfStocks"
# average number of stocks
strategy.avgNumberOfStocks <- sum(strat.EqualWeights$NumberOfStocks)/length(strat.EqualWeights$NumberOfStocks)

bench.EqualWeights <- aggregate(Id ~ ym, data = BRIC.benchmark, FUN=function(x) length(unique(x)))
colnames(bench.EqualWeights)[2] <- "NumberOfStocks"
# average number of stocks
benchmark.avgNumberOfStocks <- sum(bench.EqualWeights$NumberOfStocks)/length(bench.EqualWeights$NumberOfStocks)

#6 Portfolio Statistics All teams should perform the following analyses:

  • A clear description of the strategy design (approach, weighting, rebalancing,…)
  • Portfolio characteristics (ann. turnover, avg. number of stocks, portfolio concentration)
  • Performance statistics (return, volatility, Sharpe ratio, outperformance, tracking error, information ratio, all annualized)
  • Visualize cumulative performance and outperformance
  • Regress portfolio performance on FF5FM + Momentum for style analysis
  • Provide the time-series of the your strategy, the benchmark, and Fama-French factors as RData file

6.1 Weight column for BRIC.strategy

NOTE RUN only one of the 6.0.x junks ### 6.1.1 Equal weights // Every stock has the same weight within a ym

# assign a new working variable
strategy <- BRIC.strategy

strategy.EqualWeights <- aggregate(Id ~ ym, data = strategy, FUN=function(x) length(unique(x)))
colnames(strategy.EqualWeights)[2] <- "NumberOfStocks"

## join value weights to stocks
strategy <- inner_join(x = strategy, y = strategy.EqualWeights, by = "ym")

## calculate value weight
strategy$Weight <- 1/strategy$NumberOfStocks

## calculate value weight excess return / return
strategy$wRet <- strategy$Weight*strategy$RET.USD
strategy$wExRet <- strategy$Weight * strategy$RiRF

# TOP 10 ----
strategy.EqualWeights$weight <- 1/strat.EqualWeights$NumberOfStocks
strategy.topTenBricT <- mean(strategy.EqualWeights$weight)

6.1.2 Value weights

// every stock has a weight according to its marketcap in the ym

# assign a new working variable
strategy <- BRIC.strategy

# value weight returns
## calculate monthly market value over all stocks
strategy.valueWeights <- aggregate(LMV.USD ~ ym, data = strategy, FUN = sum)
colnames(strategy.valueWeights)[2] <- "TotalValue"

## join value weights to stocks
strategy <- inner_join(x = strategy, y = strategy.valueWeights, by = "ym")

## calculate value weight
strategy$Weight <- strategy$LMV.USD/strategy$TotalValue

## calculate value weight excess return / return
strategy$wRet <- strategy$Weight*strategy$RET.USD
strategy$wExRet <- strategy$Weight * strategy$RiRF

# TOP 10 ----
strategy_topTen <- strategy %>% arrange(desc(Weight)) %>% group_by(ym) %>% top_n(wt=Weight,10)
strategy.topTenBricY <- aggregate(Weight ~ ym, data = strategy_topTen, FUN = sum)
strategy.topTenBricT <- mean(strategy.topTenBricY$Weight)

6.2 Strategy Statistics

6.2.1 BRIC


# RETURNS ----

# per month
strategy.retBricM <- aggregate(cbind(wRet,wExRet) ~ ym + hcjun, data = strategy,FUN = sum)

# per year
strategy.retBricY <- aggregate(cbind(wRet,wExRet) ~ hcjun, data = strategy.retBricM,FUN = mean)
# annualisation
strategy.retBricY$wRet <- strategy.retBricY$wRet * 12
strategy.retBricY$wExRet <- strategy.retBricY$wExRet * 12
# mean return of whole period
strategy.retBricT <- mean(strategy.retBricY$wRet) # 15.329091 %

# mean excess return of whole period
strategy.retExBricT <- mean(strategy.retBricY$wExRet) # 13.111509 %

# STANDARD DEVIATION ----

# we calculate the sd out of the annualised portfolio returns
strategy.sdBricT <- sd(strategy.retBricY$wRet) # 37.155688

# SHARP RATIO ----

strategy.srBricT <- strategy.retExBricT/strategy.sdBricT # 0.352880

# MAX DRAWDOWN ----

drawdown <- function(ret) {
   cum.ret  <- c(0, cumsum(ret))
   drawdown <- cum.ret - cummax(cum.ret)
   return(tail(drawdown, -1))
}

maxdrawdown <- function(ret)min(drawdown(ret))
ret <- strategy.retBricY$wRet
strategy.mdBricT <- maxdrawdown(ret) # -99.1467

# TRACKING ERROR ----

# merge portfolio returns and benchmark returns
strategy_benchmark <- inner_join(x = strategy.retBricY, y = benchmark.retBricY, by = "hcjun")
colnames(strategy_benchmark)[2] <- "wRet_strategy"
colnames(strategy_benchmark)[3] <- "wExRet_strategy"
colnames(strategy_benchmark)[4] <- "wRet_benchmark"
colnames(strategy_benchmark)[5] <- "wExRet_benchmark"
strategy_benchmark$pf_activeReturn <- strategy_benchmark$wRet_strategy - strategy_benchmark$wRet_benchmark
strategy.teBricT <- sd(strategy_benchmark$pf_activeReturn) # 26.831411 %

# INFROMATION RATIO ----

strategy.irBricT <- mean(strategy_benchmark$pf_activeReturn)/strategy.teBricT # 0.26754

6.2.2 By country

IMPORTANT NOTE: If we would like to apply the whole strategy for a country stand-alone we would have to filter in 5.3 for a country and run the “BRIC”-code in part 6. Here we calculate statistics for single countries, but they’re based on a portfolio selection with stocks of the whole BRIC region. –> strong BIAS


# RETURNS

# per month
strategy.retCountryM <- aggregate(cbind(wRet,wExRet) ~ country.x + ym + hcjun, data = strategy,FUN = sum)
# per year
strategy.retCountryY <- aggregate(cbind(wRet,wExRet) ~ country.x + hcjun, data = strategy.retCountryM,FUN = mean)
# annualisation
strategy.retCountryY$wRet <- strategy.retCountryY$wRet * 12
strategy.retCountryY$wExRet <- strategy.retCountryY$wExRet * 12
# mean excess return and return of whole period
strategy.retCountryT <- aggregate(cbind(wRet,wExRet) ~ country.x, data = strategy.retCountryY,FUN = mean)

# STANDARD DEVIATION
strategy.sdCountryT <- aggregate(wRet ~ country.x, data = strategy.retCountryY, FUN = sd)
colnames(strategy.sdCountryT)[2] <- "SDwholeperiod"

# SHARP RATIO

strategy.srCountryT = inner_join(x = strategy.retCountryT, y = strategy.sdCountryT, by = "country.x" )
strategy.srCountryT$SR <- strategy.srCountryT$wExRet/strategy.srCountryT$SDwholeperiod

# MAX DRAWDOWN
# td


# TRACKING ERROR

# merge portfolio returns and benchmark returns
strategy_benchmark_c <- inner_join(x = strategy.retCountryY, y = benchmark.retCountryY, by = c("hcjun","country.x"))
colnames(strategy_benchmark_c)[3] <- "wRet_portfolio"
colnames(strategy_benchmark_c)[4] <- "wExRet_portfolio"
colnames(strategy_benchmark_c)[5] <- "wRet_benchmark"
colnames(strategy_benchmark_c)[6] <- "wExRet_benchmark"
strategy_benchmark_c$pf_activeReturn <- strategy_benchmark_c$wRet_portfolio - strategy_benchmark_c$wRet_benchmark

strategy.teCountryT <- aggregate(pf_activeReturn ~ country.x, data = strategy_benchmark_c, FUN = sd)
colnames(strategy.teCountryT)[2] <- "TrackingError"

# INFROMATION RATIO
strategy.irCountryT_intermediate <- aggregate(pf_activeReturn ~ country.x, data = strategy_benchmark_c, FUN = mean)
colnames(strategy.irCountryT_intermediate)[2] <- "meanActiveRet"

strategy.irCountryT <- inner_join(x = strategy.teCountryT, y = strategy.irCountryT_intermediate, by = "country.x")
strategy.irCountryT$InformationRatio <- strategy.irCountryT$meanActiveRet / strategy.irCountryT$TrackingError

6.3 Benchmark Statistics

# mean return of whole period
benchmark.retBricT <- mean(benchmark.retBricY$wRet) 

# mean excess return of whole period
benchmark.retExBricT <- mean(benchmark.retBricY$wExRet)

# STANDARD DEVIATION

# we calculate the sd out of the annualised portfolio returns
benchmark.sdBricT <- sd(benchmark.retBricY$wRet) 

# SHARP RATIO

benchmark.srBricT <- benchmark.retExBricT/benchmark.sdBricT 

# MAX DRAWDOWN

drawdown <- function(ret) {
   cum.ret  <- c(0, cumsum(ret))
   drawdown <- cum.ret - cummax(cum.ret)
   return(tail(drawdown, -1))
}

maxdrawdown <- function(ret)min(drawdown(ret))
ret <- benchmark.retBricY$wRet
benchmark.mdBricT <- maxdrawdown(ret) 

# TRACKING ERROR

# merge portfolio returns and benchmark returns
benchmark_benchmark <- inner_join(x = benchmark.retBricY, y = benchmark.retBricY, by = "hcjun")
colnames(benchmark_benchmark)[2] <- "wRet_benchmark"
colnames(benchmark_benchmark)[3] <- "wExRet_benchmark"
colnames(benchmark_benchmark)[4] <- "wRet_benchmark"
colnames(benchmark_benchmark)[5] <- "wExRet_benchmark"
benchmark_benchmark$pf_activeReturn <- benchmark_benchmark$wRet_benchmark - benchmark_benchmark$wRet_benchmark
benchmark.teBricT <- sd(benchmark_benchmark$pf_activeReturn)

# INFROMATION RATIO

benchmark.irBricT <- mean(benchmark_benchmark$pf_activeReturn)/benchmark.teBricT

# TOP 10 ----
benchmark_topTen <- BRIC.benchmark %>% arrange(desc(ValueWeight)) %>% group_by(ym) %>% top_n(wt=ValueWeight,10)
benchmark.topTenBricY <- aggregate(ValueWeight ~ ym, data = benchmark_topTen, FUN = sum)
benchmark.topTenBricT <- mean(benchmark.topTenBricY$ValueWeight)

6.4 Turnover

library(reshape)
library(xts)

# strategy turnover ----
# get intermediate data frame
turnover_calc <- strategy

s_weights <- subset(turnover_calc,select= c("ym","Weight","Id"))
s_weights <-reshape(s_weights, idvar = "ym", timevar = "Id", direction = "wide")
s_weights <-as.xts(s_weights)
s_weights[is.na(s_weights)]=0

s_lead_weights <- as.data.frame(s_weights)
s_lead_weights <-s_lead_weights %>% mutate_all(lead)
as.data.frame(s_lead_weights)

s_lead_weights<-as.data.frame(s_lead_weights)
s_weights<-as.data.frame(s_weights)

s_turnover_weights<-as.data.frame(txns <- s_lead_weights - s_weights) #s_tunover_weights - stuff inside the bracker in the fromula
s_turnover_weights[is.na(s_turnover_weights)]=0
s_turnover_pattern <- as.data.frame(rowSums(abs(s_turnover_weights[,1:length(s_turnover_weights)])),order.by=index(s_turnover_weights))
colnames(s_turnover_pattern)[1] <- "one"

s_turnover_pattern<-as.data.frame(s_turnover_pattern)
strategy.turnover <- (sum(s_turnover_pattern$one) / (2*nrow(s_turnover_pattern)))

# benchmark turnover ----
# get intermediate data frame
turnover_calc <- BRIC.benchmark

s_weights <- subset(turnover_calc,select= c("ym","ValueWeight","Id"))
s_weights <-reshape(s_weights, idvar = "ym", timevar = "Id", direction = "wide")
s_weights <-as.xts(s_weights)
s_weights[is.na(s_weights)]=0

s_lead_weights <- as.data.frame(s_weights)
s_lead_weights <-s_lead_weights %>% mutate_all(lead)
as.data.frame(s_lead_weights)

s_lead_weights<-as.data.frame(s_lead_weights)
s_weights<-as.data.frame(s_weights)

s_turnover_weights<-as.data.frame(txns <- s_lead_weights - s_weights) #s_tunover_weights - stuff inside the bracker in the fromula
s_turnover_weights[is.na(s_turnover_weights)]=0
s_turnover_pattern <- as.data.frame(rowSums(abs(s_turnover_weights[,1:length(s_turnover_weights)])),order.by=index(s_turnover_weights))
colnames(s_turnover_pattern)[1] <- "one"

s_turnover_pattern<-as.data.frame(s_turnover_pattern)
benchmark.turnover <- (sum(s_turnover_pattern$one) / (2*nrow(s_turnover_pattern)))

6.5 Saving Statistics into a single data frame

full_BRIC_ValueWeight <- c(strategy.retBricT,strategy.retExBricT,strategy.sdBricT,strategy.srBricT,strategy.mdBricT,strategy.teBricT,strategy.irBricT, strategy.avgNumberOfStocks, strategy.topTenBricT, strategy.turnover)

full_BRIC_Benchmark <- c(benchmark.retBricT,benchmark.retExBricT,benchmark.sdBricT,benchmark.srBricT,benchmark.mdBricT,benchmark.teBricT,benchmark.irBricT, benchmark.avgNumberOfStocks, benchmark.topTenBricT, benchmark.turnover)

full_BRIC_ValueWeight

7 Spanning tests (factor exposure)

# join factors, strategy and benchmark ----
spanning_1 <- left_join(x = factors, y = strategy.retBricM, by = "ym")
spanning <- left_join(x = spanning_1, y = market.retBricM, by = "ym")
colnames(spanning)[8] <- "Strategy_RET"
colnames(spanning)[9] <- "Strategy_RiRF"
colnames(spanning)[11] <- "Market_RET"
colnames(spanning)[12] <- "Market_RiRF"

# correlation matrix between factors

head(spanning)

dim(spanning) # 280 (24 years * 12 months) x 5

## cor(spanning[,-"ym"]) # correlation matrix between factors for the BRIC region

summary(spanning) # to use for a table

# Spanning Tests ----
## FF3FM
summary(lm(data=spanning, formula = Strategy_RiRF ~ Market_RiRF + SMB + HML))

## FF5FM
summary(lm(data=spanning, formula = Strategy_RiRF ~ Market_RiRF + SMB + HML + CMA + RMW))

## FF3FM + MOM
summary(lm(data=spanning, formula = Strategy_RiRF ~ Market_RiRF + SMB + HML + MOM))

## FF5FM + MOM
summary(lm(data=spanning, formula = Strategy_RiRF ~ Market_RiRF + SMB + HML + CMA + RMW + MOM))

8 Plots and Visualisation

List of plots: 1) Cummulative performance Benchmark vs Strategy BRIC // VINIT/MANU revisit 2) Single factors vs multifactor portfolio in risk-return space // MANU revisit 3) Evolution of MarketCap weights per country –> regional weighting (implicit) // ?? // use GDP plot code and update it

List of tables: 1) Performance and risk // MANU revisit –> JOHANNES gives the data 2) Investability // MANU revisit 3) Spanning tests_Style exposure //

Table/Plot: 1) Strategy BRIC vs Countries stand alone // JOHANNES ## Tables done 2) Strategy parts stand alone and/or 2 combined vs 3ple sort // Johannes ## Tables done

8.1 Benchmark vs Strategy

8.2 Factor Returns

8.3 Strategy Comparison (3factor, 2factor, 1factor)

8.4 Evolution of MarketCap Weights

LS0tDQp0aXRsZTogIkJSSUNfcHJvamVjdCINCmF1dGhvcjogDQogIG5hbWU6IE1hbnVlbCBTY2hyZWliZXINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogdW5pdGVkDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgbGF0ZXhfZW5naW5lOiBwZGZsYXRleA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaGVhZGVyLWluY2x1ZGVzOg0KICAgLSBcdXNlcGFja2FnZXthbXNtYXRofQ0KICAgLSBcdXNlcGFja2FnZXthbXNmb250c30NCi0tLQ0KDQoqKkJSSUMgUHJvamVjdCoqDQpgYGB7cn0NCiMgY2xlYXIgd29ya3NwYWNlDQojI3JtKGxpc3Q9bHMoKSkNCmBgYA0KZ2V0dGluZyB0aGUgY3VycmVudCBXRA0KDQpgYGB7cn0NCmdldHdkKCkNCmBgYA0KDQojIDAuMSBMb2FkaW5nIExpYnJhcmllcw0KDQpgYGB7cn0NCiMgbG9hZGluZyBsaWJyYXJpZXMNCmxpYnJhcnkoZGF0YS50YWJsZSkgIyBleHRlbnNpb24gb2YgdGhlIGRhdGEuZnJhbWUgcGFja2FnZS4gSXQgaXMgd2lkZWx5IHVzZWQgZm9yIGZhc3QgYWdncmVnYXRpb24gb2YgbGFyZ2UgZGF0YXNldHMsIGxvdyBsYXRlbmN5IGFkZC91cGRhdGUvcmVtb3ZlIG9mIGNvbHVtbnMsIHF1aWNrZXIgb3JkZXJlZCBqb2lucywgYW5kIGEgZmFzdCBmaWxlIHJlYWRlci4NCmxpYnJhcnkoZHBseXIpICMgZGF0YSBtYW5pcHVsYXRpb24gcGFja2FnZQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHpvbykgIyBtZXRob2RzIGZvciB0b3RhbGx5IG9yZGVyZWQgaW5kZXhlZCBvYnNlcnZhdGlvbnMuIEl0IGFpbXMgYXQgcGVyZm9ybWluZyBjYWxjdWxhdGlvbnMgY29udGFpbmluZyBpcnJlZ3VsYXIgdGltZSBzZXJpZXMgb2YgbnVtZXJpYyB2ZWN0b3JzLCBtYXRyaWNlcyAmIGZhY3RvcnMNCmxpYnJhcnkoc3RhdHMpDQpsaWJyYXJ5KHV0aWxzKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShyZXNoYXBlMikNCmBgYA0KIyAwLjIgTG9hZGluZyBpbiB0aGUgUi5kYXRhDQoNCkRhdGEgY29sdW1uIGRlc2NyaXB0aW9ucyAoV29ybGRzY29wZSk6DQpodHRwczovL3d3dy5wcm9mZXNzb3JzLndpLnR1bS5kZS9maWxlYWRtaW4vdzAwYmNhL2ZtL1dvcmxkc2NvcGVfRGF0YV9EZWZpbml0aW9uX0d1aWRlX0lzc3VlXzE1LnBkZg0KDQpodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xWXR1Sml2NjBRNm5LSWFGSkxRWTYwc0dRRXJic2xfOG52UGRVSG12Tzh2TS9lZGl0P3VzcD1zaGFyaW5nDQoNCiMjIDAuMi4xIExvYWRpbmcgZGF0YSBKb2hhbm5lcw0KYGBge3J9DQptZW1vcnkubGltaXQoOTk5OTk5OTk5OSkNCiMgbG9hZGluZyBSLmRhdGEgQlJJQyBtb250aGx5DQpsb2FkKCJDOi9Vc2Vycy9qb2hhbi9Eb2N1bWVudHMvQlJJQ19Bc3NldF9QcmljaW5nX1Byb2plY3QvQlJJQ19tb250aGx5LlJEYXRhIikNCg0KIyBsb2FkaW5nIFIuZGF0YSBCUklDIHN0YXRpYw0KbG9hZCgiQzovVXNlcnMvam9oYW4vRG9jdW1lbnRzL0JSSUNfQXNzZXRfUHJpY2luZ19Qcm9qZWN0L0JSSUNfc3RhdGljLlJEYXRhIikNCg0KIyBsb2FkaW5nIFIuZGF0YSBCUklDIHllYXJseQ0KbG9hZCgiQzovVXNlcnMvam9oYW4vRG9jdW1lbnRzL0JSSUNfQXNzZXRfUHJpY2luZ19Qcm9qZWN0L0JSSUNfeWVhcmx5LlJEYXRhIikNCg0KYGBgDQojIyAwLjIuMiBMb2FkaW5nIGRhdGEgTWFudWVsDQpgYGB7cn0NCiMgbG9hZGluZyBSLmRhdGEgQlJJQyBtb250aGx5DQpsb2FkKCIvVXNlcnMvTWFudS9EZXNrdG9wL1RVTV9NYXN0ZXJfTWd0X1RlY2hub2xvZ3kvVFVNX1NTXzIxL0VtcGlyaWNhbCBBc3NldCBQcmljaW5nIHNlbWluYXIvU2VtaW5hciBUaGVzaXMvQlJJQ19kYXRhL0JSSUNfbW9udGhseS5SRGF0YSIpDQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiL1VzZXJzL01hbnUvRGVza3RvcC9UVU1fTWFzdGVyX01ndF9UZWNobm9sb2d5L1RVTV9TU18yMS9FbXBpcmljYWwgQXNzZXQgUHJpY2luZyBzZW1pbmFyL1NlbWluYXIgVGhlc2lzL0JSSUNfZGF0YS9CUklDX3N0YXRpYy5SRGF0YSIpDQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiL1VzZXJzL01hbnUvRGVza3RvcC9UVU1fTWFzdGVyX01ndF9UZWNobm9sb2d5L1RVTV9TU18yMS9FbXBpcmljYWwgQXNzZXQgUHJpY2luZyBzZW1pbmFyL1NlbWluYXIgVGhlc2lzL0JSSUNfZGF0YS9CUklDX3llYXJseS5SRGF0YSIpDQpgYGANCg0KIyMgMC4yLjMgTG9hZGluZyBkYXRhIFZpbml0DQpgYGB7cn0NCiMgbG9hZGluZyBSLmRhdGEgQlJJQyBtb250aGx5DQpsb2FkKCIvVXNlcnMvdmluaXRrdW1hci9EZXNrdG9wL1NTMjAyMS9DYXNlcyBpbiBGaW5hbmNlL0JSSUNfQXNzZXRfUHJpY2luZ19Qcm9qZWN0L0JSSUNfRGF0YS9CUklDX21vbnRobHkuUkRhdGEiKQ0KDQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiL1VzZXJzL3Zpbml0a3VtYXIvRGVza3RvcC9TUzIwMjEvQ2FzZXMgaW4gRmluYW5jZS9CUklDX0Fzc2V0X1ByaWNpbmdfUHJvamVjdC9CUklDX0RhdGEvQlJJQ19zdGF0aWMuUkRhdGEiKQ0KDQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiL1VzZXJzL3Zpbml0a3VtYXIvRGVza3RvcC9TUzIwMjEvQ2FzZXMgaW4gRmluYW5jZS9CUklDX0Fzc2V0X1ByaWNpbmdfUHJvamVjdC9CUklDX0RhdGEvQlJJQ195ZWFybHkuUkRhdGEiKQ0KYGBgDQojIyAwLjIuNCBMb2FkaW5nIGRhdGEgQ2hhbmRyYQ0KYGBge3J9DQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiL1VzZXJzL2NnL0Rlc2t0b3AvVFVNL1NTMjEvRW1waXJpY2FsIEFzc2V0IFByaWNpbmcgU2VtaW5hci9QcmVzZW50YXRpb24vQlJJQ19EYXRhL0JSSUNfbW9udGhseS5SRGF0YSIpDQoNCiMgbG9hZGluZyBSLmRhdGEgQlJJQyB5ZWFybHkNCmxvYWQoIi9Vc2Vycy9jZy9EZXNrdG9wL1RVTS9TUzIxL0VtcGlyaWNhbCBBc3NldCBQcmljaW5nIFNlbWluYXIvUHJlc2VudGF0aW9uL0JSSUNfRGF0YS9CUklDX3llYXJseS5SRGF0YSIpDQoNCiMgbG9hZGluZyBSLmRhdGEgQlJJQyBzdGF0aWMNCmxvYWQoIi9Vc2Vycy9jZy9EZXNrdG9wL1RVTS9TUzIxL0VtcGlyaWNhbCBBc3NldCBQcmljaW5nIFNlbWluYXIvUHJlc2VudGF0aW9uL0JSSUNfRGF0YS9CUklDX3N0YXRpYy5SRGF0YSIpDQpgYGANCg0KDQojIERhdGEgcHJlcGFyYXRpb24NCg0KIyMgMSBTYXZlIHJhdyBkYXRhIGFuZCBhZGp1c3QgZGF0ZSByYW5nZQ0KDQpgYGB7cn0NCiMwIHNhdmUgcmF3IGRhdGENCkJSSUMubW9udGhseS5yYXcgPC0gQlJJQy5tb250aGx5DQpCUklDLnllYXJseS5yYXcgPC0gQlJJQy55ZWFybHkNCg0KIzEgYWRqdXN0IGRhdGUgcmFuZ2UgKGZyb20gSnVseSAxOTk0IHRvIERlY2VtYmVyIDIwMTgpDQojMS4xIGxlYXZlIHJhdyBkYXRhIHdpdGggZGF0ZSBhZGp1c3RtZW50DQpCUklDLm1vbnRobHkud2l0aE5BIDwtIHN1YnNldChCUklDLm1vbnRobHkucmF3LCBEYXRlID49ICIxOTk0LTA2LTMwIiAmIERhdGUgPD0gIjIwMTktMDItMDEiKQ0KQlJJQy55ZWFybHkud2l0aE5BIDwtIHN1YnNldChCUklDLnllYXJseS5yYXcsIFlFQVIgPj0gIjE5OTQiICYgWUVBUiA8PSAiMjAxOSIpDQojMS4yIHdvcmtpbmcgZGF0YWZyYW1lDQpCUklDLm1vbnRobHkgPC0gc3Vic2V0KEJSSUMubW9udGhseSwgRGF0ZSA+PSAiMTk5NC0wNi0zMCIgJiBEYXRlIDw9ICIyMDE5LTAyLTAxIikNCkJSSUMueWVhcmx5IDwtIHN1YnNldChCUklDLnllYXJseSwgWUVBUiA+PSAiMTk5NCIgJiBZRUFSIDw9ICIyMDE5IikNCmBgYA0KDQoNCiMjIDIgQlJJQy5tb250aGx5IGRhdGEgcHJlcGFyYXRpb24NCmF0IHRoaXMgcG9pbnQgb2YgdGltZSB0aGUgZGF0YSBzaGVldCBpcyBzdGlsbCBiYWxhbmNlZCwgdGhlcmVmb3JlIHdlIGNhbiB1c2UgdGhlIHNoaWZ0IGZ1bmN0aW9uDQpgYGB7cn0NCiMgYWRkIGEgbmV3IGNvbHVtbiBmb3IgdGhlIGxhZ2dlZCBNVi5VU0QgKHRoaXMgaXMgdGhlIE1WLlVTRCBmcm9tIHRoZSBwcmV2aW91cyBtb250aCkgDQpCUklDLm1vbnRobHlbLCBMTVYuVVNEIDo9IGxhZygoTVYuVVNEKSwxKSwgYnkgPUlkXQ0KDQojIGFkZCBhIG5ldyBjb2x1bW4gZm9yIHZvbGF0aWxpdHkNCkJSSUMubW9udGhseVssIHZvbGF0aWxpdHkgOj0gbGFnKHJvbGxhcHBseXIoUkVULlVTRCwgMzYsIHNkLCBmaWxsID0gTkEsIHBhcnRpYWwgPSAxMiksMSksIGJ5ID1JZF0NCg0KIyBhZGQgMTIgbmV3IGNvbHVtbnMgZm9yIGxhc3QgMTIgbW9udGhzIHJldHVybnMNCkJSSUMubW9udGhseVssIGxhZzEgOj0gbGFnKChSRVQuVVNEKSwxKSwgYnkgPUlkXQ0KQlJJQy5tb250aGx5WywgbGFnMiA6PSBsYWcoKFJFVC5VU0QpLDIpLCBieSA9SWRdDQpCUklDLm1vbnRobHlbLCBsYWczIDo9IGxhZygoUkVULlVTRCksMyksIGJ5ID1JZF0NCkJSSUMubW9udGhseVssIGxhZzQgOj0gbGFnKChSRVQuVVNEKSw0KSwgYnkgPUlkXQ0KQlJJQy5tb250aGx5WywgbGFnNSA6PSBsYWcoKFJFVC5VU0QpLDUpLCBieSA9SWRdDQpCUklDLm1vbnRobHlbLCBsYWc2IDo9IGxhZygoUkVULlVTRCksNiksIGJ5ID1JZF0NCkJSSUMubW9udGhseVssIGxhZzcgOj0gbGFnKChSRVQuVVNEKSw3KSwgYnkgPUlkXQ0KQlJJQy5tb250aGx5WywgbGFnOCA6PSBsYWcoKFJFVC5VU0QpLDgpLCBieSA9SWRdDQpCUklDLm1vbnRobHlbLCBsYWc5IDo9IGxhZygoUkVULlVTRCksOSksIGJ5ID1JZF0NCkJSSUMubW9udGhseVssIGxhZzEwIDo9IGxhZygoUkVULlVTRCksMTApLCBieSA9SWRdDQpCUklDLm1vbnRobHlbLCBsYWcxMSA6PSBsYWcoKFJFVC5VU0QpLDExKSwgYnkgPUlkXQ0KQlJJQy5tb250aGx5WywgbGFnMTIgOj0gbGFnKChSRVQuVVNEKSwxMiksIGJ5ID1JZF0NCg0KdHlwZW9mKEJSSUMubW9udGhseSRsYWcxKQ0KIyBuZWdhdGl2ZSB2YWx1ZXMgYXJlIHJlcGxhY2VkIHRvIDANCiNpZmVsc2UoQlJJQy5tb250aGx5JGxhZzE8PTAsMCxpZmVsc2UoQlJJQy5tb250aGx5JGxhZzE+MCwxLE5BKSkNCkJSSUMubW9udGhseSRsYWcxIDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzEsQlJJQy5tb250aGx5JGxhZzE8PTAsMCkNCkJSSUMubW9udGhseSRsYWcyIDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzIsQlJJQy5tb250aGx5JGxhZzI8PTAsMCkNCkJSSUMubW9udGhseSRsYWczIDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzMsQlJJQy5tb250aGx5JGxhZzM8PTAsMCkNCkJSSUMubW9udGhseSRsYWc0IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzQsQlJJQy5tb250aGx5JGxhZzQ8PTAsMCkNCkJSSUMubW9udGhseSRsYWc1IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzUsQlJJQy5tb250aGx5JGxhZzU8PTAsMCkNCkJSSUMubW9udGhseSRsYWc2IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzYsQlJJQy5tb250aGx5JGxhZzY8PTAsMCkNCkJSSUMubW9udGhseSRsYWc3IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzcsQlJJQy5tb250aGx5JGxhZzc8PTAsMCkNCkJSSUMubW9udGhseSRsYWc4IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzgsQlJJQy5tb250aGx5JGxhZzg8PTAsMCkNCkJSSUMubW9udGhseSRsYWc5IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzksQlJJQy5tb250aGx5JGxhZzk8PTAsMCkNCkJSSUMubW9udGhseSRsYWcxMCA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWcxMCxCUklDLm1vbnRobHkkbGFnMTA8PTAsMCkNCkJSSUMubW9udGhseSRsYWcxMSA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWcxMSxCUklDLm1vbnRobHkkbGFnMTE8PTAsMCkNCkJSSUMubW9udGhseSRsYWcxMiA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWcxMixCUklDLm1vbnRobHkkbGFnMTI8PTAsMCkNCg0KIyBwb3NpdGl2ZSB2YWx1ZXMgYXJlIHJlcGxhY2VkIHRvIDENCkJSSUMubW9udGhseSRsYWcxIDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzEsQlJJQy5tb250aGx5JGxhZzE+MCwxKQ0KQlJJQy5tb250aGx5JGxhZzIgPC0gcmVwbGFjZShCUklDLm1vbnRobHkkbGFnMixCUklDLm1vbnRobHkkbGFnMj4wLDEpDQpCUklDLm1vbnRobHkkbGFnMyA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWczLEJSSUMubW9udGhseSRsYWczPjAsMSkNCkJSSUMubW9udGhseSRsYWc0IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzQsQlJJQy5tb250aGx5JGxhZzQ+MCwxKQ0KQlJJQy5tb250aGx5JGxhZzUgPC0gcmVwbGFjZShCUklDLm1vbnRobHkkbGFnNSxCUklDLm1vbnRobHkkbGFnNT4wLDEpDQpCUklDLm1vbnRobHkkbGFnNiA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWc2LEJSSUMubW9udGhseSRsYWc2PjAsMSkNCkJSSUMubW9udGhseSRsYWc3IDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzcsQlJJQy5tb250aGx5JGxhZzc+MCwxKQ0KQlJJQy5tb250aGx5JGxhZzggPC0gcmVwbGFjZShCUklDLm1vbnRobHkkbGFnOCxCUklDLm1vbnRobHkkbGFnOD4wLDEpDQpCUklDLm1vbnRobHkkbGFnOSA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWc5LEJSSUMubW9udGhseSRsYWc5PjAsMSkNCkJSSUMubW9udGhseSRsYWcxMCA8LSByZXBsYWNlKEJSSUMubW9udGhseSRsYWcxMCxCUklDLm1vbnRobHkkbGFnMTA+MCwxKQ0KQlJJQy5tb250aGx5JGxhZzExIDwtIHJlcGxhY2UoQlJJQy5tb250aGx5JGxhZzExLEJSSUMubW9udGhseSRsYWcxMT4wLDEpDQpCUklDLm1vbnRobHkkbGFnMTIgPC0gcmVwbGFjZShCUklDLm1vbnRobHkkbGFnMTIsQlJJQy5tb250aGx5JGxhZzEyPjAsMSkNCg0KQlJJQy5tb250aGx5JGxhZ1N1bSA8LSBCUklDLm1vbnRobHkkbGFnMSArIEJSSUMubW9udGhseSRsYWcyICsgQlJJQy5tb250aGx5JGxhZzMgKyBCUklDLm1vbnRobHkkbGFnNCArIEJSSUMubW9udGhseSRsYWc1ICsgQlJJQy5tb250aGx5JGxhZzYgKyBCUklDLm1vbnRobHkkbGFnNyArIEJSSUMubW9udGhseSRsYWc4ICsgQlJJQy5tb250aGx5JGxhZzkgKyBCUklDLm1vbnRobHkkbGFnMTAgKyBCUklDLm1vbnRobHkkbGFnMTEgKyArIEJSSUMubW9udGhseSRsYWcxMg0KDQpCUklDLm1vbnRobHlbICwgcGYubW9tZW50dW0gOj0gaWZlbHNlKGxhZ1N1bT49OCwiV2lubmVyIixpZmVsc2UobGFnU3VtIDwgOCwiTG9vc2VyIixOQSkpXQ0KDQojIGRlbGV0ZSBhbGwgZW50cnlzIGJlZm9yZSBKdWx5IDE5OTQNCkJSSUMubW9udGhseSA8LSBzdWJzZXQoQlJJQy5tb250aGx5LCBEYXRlID49ICIxOTk0LTA3LTI5IiAmIERhdGUgPD0gIjIwMTktMDItMDEiKQ0KDQojIGNhbGN1bGF0ZSBNVi5VU0QuSnVuZSBmb3IgZXZlcnkgY29sdW1uDQojIGhlbHAgY29sdW1ucw0KQlJJQy5tb250aGx5Wyxtb250aCA6PSBtb250aChEYXRlKV0NCkJSSUMubW9udGhseVsseWVhciA6PSB5ZWFyKERhdGUpXQ0KQlJJQy5tb250aGx5WyxoY2p1biA6PSBpZmVsc2UobW9udGg+PTcseWVhcix5ZWFyLTEpXQ0KIyBNVi5VU0QuSnVuZSBjb2x1bW4NCmludGVybWVkaWF0ZSA8LSBmaWx0ZXIoQlJJQy5tb250aGx5LEJSSUMubW9udGhseSRtb250aCA9PSA3KQ0KIyBtaW5pbWlzZSBmb3Igam9pbg0KaW50ZXJtZWRpYXRlIDwtIHN1YnNldChpbnRlcm1lZGlhdGUsIHNlbGVjdCA9IGMoIklkIiwiTE1WLlVTRCIsImhjanVuIikpDQpjb2xuYW1lcyhpbnRlcm1lZGlhdGUpWzJdIDwtICJNVi5VU0QuSnVuZSINCkJSSUMubW9udGhseSA8LSBzdWJzZXQoQlJJQy5tb250aGx5LCBzZWxlY3QgPSBjKCJJZCIsImNvdW50cnkiLCJEYXRlIiwiTVYiLCJNVi5VU0QiLCJMTVYuVVNEIiwiUkVUIiwiUkVULlVTRCIsInZvbGF0aWxpdHkiLCJwZi5tb21lbnR1bSIsInltIiwiaGNqdW4iLCJ5ZWFyIiwibW9udGgiKSkNCg0KIyBpbm5lciBqb2luIGF1dG9tYXRpY2FsbHkgZGVsZXRlcyB2YWx1ZXMgd2hlcmUgTVYuVVNELkp1bmUgaXMgbm90IGF2YWlsYWJsZQ0KQlJJQy5tb250aGx5IDwtIGlubmVyX2pvaW4oeCA9IEJSSUMubW9udGhseSx5ID0gaW50ZXJtZWRpYXRlLCBieSA9IGMoIklkIiwiaGNqdW4iKSkNCiMgb3JkZXIgQlJJQy5tb250aGx5DQpCUklDLm1vbnRobHkgPC0gc3Vic2V0KEJSSUMubW9udGhseSwgc2VsZWN0ID0gYygiSWQiLCJjb3VudHJ5IiwiRGF0ZSIsIk1WIiwiTVYuVVNEIiwiTE1WLlVTRCIsIk1WLlVTRC5KdW5lIiwiUkVUIiwiUkVULlVTRCIsInZvbGF0aWxpdHkiLCJwZi5tb21lbnR1bSIsInltIiwiaGNqdW4iLCJ5ZWFyIiwibW9udGgiKSkNCmBgYA0KDQojIyAyLjEgUmF3IGNvZGUgdG8gcmVtb3ZlIE5BcyAoQlJJQy5tb250aGx5KQ0KDQpgYGB7cn0NCiMgZGVsZXRlIG5hJ3MsIHNldCAwIGFuZCBjYWxjdWxhdGUgaW1wb3J0YW50IHZhbHVlcw0KIyBubyBSRVQuVVNEIGRhdGEsIG5vIE1WIG9yIG5vIExNVi5VU0QNCkJSSUMubW9udGhseSA8LSBCUklDLm1vbnRobHkgJT4lDQogIGRyb3BfbmEoUkVULlVTRCxNVixNVi5VU0QsTE1WLlVTRCxNVi5VU0QuSnVuZSx2b2xhdGlsaXR5LHBmLm1vbWVudHVtKQ0KYGBgDQoNCg0KDQojIyAzIEJSSUMueWVhcmx5IGRhdGEgcHJlcGFyYXRpb24gYW5kIHZhbHVlIGNhbGN1bGF0aW9uDQoNCmBgYHtyfQ0KIzMuMCB0aGUgQlJJQy55ZWFybHkgcGFuZWwgaGVyZSBpcyBzdGlsbCBiYWxhbmNlZCEgV2UgbmVlZCB0byBhZGQgYSBjb2x1bW4gZm9yIHRvdGFsIGFzc2V0cyB0aGUgeWVhciBiZWZvcmUgLS0tLQ0KI2FkZCB0aGUgbGFnZ2VkIFdDMDM1MDEgKHNoaWZ0ZWQgYnkgSWQpICh0aGlzIGlzIHRoZSBXQzAzNTAxIGZyb20gdGhlIHByZXZpb3VzIG1vbnRoKSANCkJSSUMueWVhcmx5WywgbGFnLnZhbHVlOj1jKDAsIFdDMDM1MDFbLS5OXSksIGJ5PUlkXSANCiMgcmVuYW1lIGNvbHVtbiB0byBMTVYuVVNEDQpjb2xuYW1lcyhCUklDLnllYXJseSlbMTA2XSA8LSAiVG90YWxBc3NldHNCZWZvcmUiDQoNCiMzLjEgYm9vayB2YWx1ZSAvIGVxdWl0eSBhbmQgcmVsYXRlZCAtLS0tDQojIGRlbGV0ZSByb3dzIHdpdGggbm8gV0MwMzUwMSAoQ29tbW9uIGVxdWl0eSkNCkJSSUMueWVhcmx5IDwtIEJSSUMueWVhcmx5ICU+JQ0KICBkcm9wX25hKFdDMDM1MDEpDQojIHNldCBXQzAzMjYzIChkZWZlcnJlZCB0YXhlcykgemVybyBpZiBOQQ0KQlJJQy55ZWFybHkkV0MwMzI2MyA8LSBCUklDLnllYXJseSRXQzAzMjYzICU+JSByZXBsYWNlX25hKDApDQojIGFkZCBjb2x1bW4gZm9yIEJvb2tWYWx1ZSAoSGFuYXVlciAyMDIwIGNhbGN1bGF0aW9uKQ0KQlJJQy55ZWFybHkkQm9va1ZhbHVlIDwtIEJSSUMueWVhcmx5JFdDMDM1MDEgKyBCUklDLnllYXJseSRXQzAzMjYzDQojIGRlbGV0ZSByb3dzIHdpdGggbmVnYXRpdmUgQm9va1ZhbHVlDQpCUklDLnllYXJseSA8LSBCUklDLnllYXJseVtCUklDLnllYXJseSRCb29rVmFsdWUgPj0gMCxdDQoNCiMzLjIgdG90YWwgYXNzZXRzIC0tLS0NCiMgZGVsZXRlIHJvd3Mgd2l0aCBubyBXQzAyOTk5ICh0b3RhbCBhc3NldHMpDQpCUklDLnllYXJseSA8LSBCUklDLnllYXJseSAlPiUNCiAgZHJvcF9uYShXQzAyOTk5KQ0KIyBkZWxldGUgcm93cyB3aXRoIG5vIFRvdGFsQXNzZXRzQmVmb3JlDQpCUklDLnllYXJseSA8LSBCUklDLnllYXJseSAlPiUNCiAgZHJvcF9uYShUb3RhbEFzc2V0c0JlZm9yZSkNCg0KIzMuMyBvcGVyYXRpbmcgcHJvZml0cyAtLS0tDQojICJUbyBoYXZlIGEgdmFsaWQgdmFsdWUsIGF0IGxlYXN0IG9uZSBvZiBjb3N0IGNvbXBvbmVudHMgY29zdCBvZiBnb29kcyBzb2xkLCBzZWxsaW5nLCBnZW5lcmFsIGFuZCBhZG1pbmlzdHJhdGl2ZSBleHBlbnNlcywgb3IgaW50ZXJlc3QgZXhwZW5zZSBtdXN0IGJlIG5vbi1taXNzaW5nLiIgKEhhbmF1ZXIsIDIwMTksIHAuIDI4NCkgLS0+IGlmIG9uZSBvZiB0aGVzZSB2YWx1ZXMgaXMgbWlzc2luZywgd2UgbXVzdCBkZWxldGUgdGhlc2Ugcm93cyBXQzAxMDAxLFdDMDEwNTEsV0MwMTEwMSxXQzAxMjUxDQojIGRlbGV0ZSByb3dzIHdoZXJlIEFMTCA0IGNvbHVtbnMgYXJlIE5BDQpCUklDLnllYXJseSA8LSBmaWx0ZXIoQlJJQy55ZWFybHksIWlzLm5hKFdDMDEwMDEpIHwgIWlzLm5hKFdDMDEwNTEpIHwgIWlzLm5hKFdDMDExMDEpIHwgIWlzLm5hKFdDMDEyNTEpKQ0KIyByZXBsYWNlIGFsbCBuYSdzIGluIHRoaXMgNCBjb2x1bW5zIHdpdGggMA0KQlJJQy55ZWFybHkkV0MwMTAwMSA8LSBCUklDLnllYXJseSRXQzAxMDAxICU+JSByZXBsYWNlX25hKDApDQpCUklDLnllYXJseSRXQzAxMDUxIDwtIEJSSUMueWVhcmx5JFdDMDEwNTEgJT4lIHJlcGxhY2VfbmEoMCkNCkJSSUMueWVhcmx5JFdDMDExMDEgPC0gQlJJQy55ZWFybHkkV0MwMTEwMSAlPiUgcmVwbGFjZV9uYSgwKQ0KQlJJQy55ZWFybHkkV0MwMTI1MSA8LSBCUklDLnllYXJseSRXQzAxMjUxICU+JSByZXBsYWNlX25hKDApDQojIGNhbGN1bGF0ZSBvcGVyYXRpbmcgcHJvZml0cyAoSGFuYXVlciwgMjAxOSwgcC4yODQpDQpCUklDLnllYXJseSRPcGVyYXRpbmdQcm9maXRzIDwtIChCUklDLnllYXJseSRXQzAxMDAxIC0gQlJJQy55ZWFybHkkV0MwMTA1MSAtIEJSSUMueWVhcmx5JFdDMDExMDEgLSBCUklDLnllYXJseSRXQzAxMjUxKQ0KDQojIDMuNCBtaW5pbWlzZSBkYXRhIGZyYW1lIC0tLS0NCiMgZm9yIEJSSUMueWVhcmx5IHdlIGtlZXA6IElkLCBjb3VudHJ5LCBJQ0JTVUMsIFlFQVIsIEJvb2tWYWx1ZSwgT3BlcmF0aW5nUHJvZml0cyBhbmQgdG90YWwgYXNzZXRzDQojIE5vdGU6IFdDMDcyMDEgaXMgbm90IHVzZWQsIGFzIG91ciBNViBzaG91bGQgYmUgdGhlIE1WIGZyb20gdGhlIG1vbnRobHkgZGF0YSBmb3IgMDYueSAhDQpCUklDLnllYXJseSA8LSBzdWJzZXQoQlJJQy55ZWFybHksIHNlbGVjdCA9IGMoIklkIiwiY291bnRyeSIsIklDQlNVQyIsIllFQVIiLCJCb29rVmFsdWUiLCJPcGVyYXRpbmdQcm9maXRzIiwiV0MwMjk5OSIsIlRvdGFsQXNzZXRzQmVmb3JlIikpDQojIHdlIHJlbmFtZSBXQzAyOTk5IHRvIHRvdGFsIGFzc2V0cw0KY29sbmFtZXMoQlJJQy55ZWFybHkpWzddIDwtICJUb3RhbEFzc2V0cyINCg0KIyAzLjUgY3JlYXRlIGEgaGVscCBjb2x1bW4gaGNkZWMgKDEgeWVhciBsYWcpIC0tLS0NCkJSSUMueWVhcmx5JGhjZGVjIDwtIEJSSUMueWVhcmx5JFlFQVIgKyAxDQpgYGANCg0KDQojIDQgRkY1Rk0gQ2FsY3VsYXRpb24NCiMjIDQuMSBBZGRpbmcgdGhlIDEtbSB0cmVhc3VyeSByYXRlIHRvIHRoZSBtb250aGx5IGRhdGENCmBgYHtyfQ0KIyBsb2FkIGRhdGEgc2hlZXQgZnJvbSBGcmVuY2gncyB3ZWJzaXRlDQpGRkRhdGEgPC0gcmVhZF9jc3YoIkZGX1Jlc2VhcmNoX0RhdGFfNV9GYWN0b3JzXzJ4My5DU1YiLCANCiAgICAgc2tpcCA9IDIpDQojIHNob3J0aW5nIGRhdGEgZnJhbWUNCm9uZV9tX3RiaWxsIDwtIGFzLmRhdGEuZnJhbWUoRkZEYXRhW2MoIlgxIiwiUkYiKV1bMTo2OTMsXSkNCiMgYWRkaW5nIGEgeW0gY29sdW1uIHRvIHJpc2sgZnJlZSByYXRlIGRhdGENCm9uZV9tX3RiaWxsJHltPC1hcy55ZWFybW9uKG9uZV9tX3RiaWxsJFgxLCAiJVkgJW0iKQ0KI2RlbGV0ZSBYMSBjb2x1bW4gDQpvbmVfbV90YmlsbCA8LSBzdWJzZXQob25lX21fdGJpbGwsc2VsZWN0ID0gYygieW0iLCJSRiIpKQ0KIyBtZXJnZSByaXNrLWZyZWUgcmF0ZSAoMSBtb250aCB0cmVhc3VyeSBiaWxsIHJhdGUpIHdpdGggbW9udGhseSBkYXRhDQpCUklDLm1vbnRobHkgPC0gbGVmdF9qb2luKHggPSBCUklDLm1vbnRobHksIHkgPSBvbmVfbV90YmlsbCwgYnkgPSAieW0iKQ0KDQojIG1ha2UgcmYgY29sdW1uIG51bWVyaWMNCkJSSUMubW9udGhseSRSRiA8LSBhcy5udW1lcmljKEJSSUMubW9udGhseSRSRikNCg0KIyBBZGQgUmlSRiAtLS0tDQpCUklDLm1vbnRobHkkUmlSRiA8LSBCUklDLm1vbnRobHkkUkVULlVTRCAtIEJSSUMubW9udGhseSRSRg0KIyBMb2NhbCBjdXJyZW5jeSBSaVJGDQpCUklDLm1vbnRobHkkUmlSRi5sb2NhbCA8LSBCUklDLm1vbnRobHkkUkVUIC0gQlJJQy5tb250aGx5JFJGDQoNCmBgYA0KIyMgNC4yIE1lcmdlIG1vbnRobHkgYW5kIGFjY291bnRpbmcgKHllYXJseSkgZGF0YQ0KTk9URTogSGVyZSB3ZSAibG9vc2UiIGFyb3VuZCA2MDAgMDAwIHJvd3MhIA0KDQpgYGB7cn0NCkJSSUMubWFpbmRhdGEgPC0gaW5uZXJfam9pbih4ID0gQlJJQy5tb250aGx5LHkgPSBCUklDLnllYXJseSwgYnkgPSBjKCJJZCIsImhjanVuIiA9ICJoY2RlYyIpKQ0KDQojIEFkZCBhIEIvTSBjb2x1bW4NCkJSSUMubWFpbmRhdGEkQk0gPC0gQlJJQy5tYWluZGF0YSRCb29rVmFsdWUgLyBCUklDLm1haW5kYXRhJE1WDQojIEFkZCBhIE9QL0JFIGNvbHVtbg0KQlJJQy5tYWluZGF0YSRPUEJFIDwtIEJSSUMubWFpbmRhdGEkT3BlcmF0aW5nUHJvZml0cyAvIEJSSUMubWFpbmRhdGEkQm9va1ZhbHVlDQojIEFkZCBhIEFzc2V0Q2hhbmdlIGNvbHVtbg0KQlJJQy5tYWluZGF0YSRBc3NldENoYW5nZSA8LSAoKEJSSUMubWFpbmRhdGEkVG90YWxBc3NldHMgLSBCUklDLm1haW5kYXRhJFRvdGFsQXNzZXRzQmVmb3JlKS9CUklDLm1haW5kYXRhJFRvdGFsQXNzZXRzQmVmb3JlKQ0KDQpCUklDLm1haW5kYXRhIDwtIHN1YnNldChCUklDLm1haW5kYXRhLCBoY2p1biA+PSAiMTk5NiIpDQpgYGANCg0KIyMgQlJFQUtQT0lOVA0KSWYgd2Ugd2FudCB0byBjYWxjdWxhdGUgZmFjdG9ycyBvciBhbnl0aGluZyBlbHNlIGZvciBjb3VudHJpZXMgc3RhbmRhbG9uZSB3ZSB3aWxsIGhhdmUgdG8gZmlsdGVyIHRoZW0gaGVyZSENCkZvciBtdWx0aXBsZSB0cnlzIHJ1biA0LjIgYWdhaW4sIHRvIHJlc2V0IEJSSUMubWFpbmRhdGENCmBgYHtyfQ0KIyBlLmcuIGZpbHRlciBmb3IgQ2hpbmENCiMjQlJJQy5tYWluZGF0YSA8LSBmaWx0ZXIoQlJJQy5tYWluZGF0YSxCUklDLm1haW5kYXRhJGNvdW50cnkueCA9PSAiQ0hOIikNCg0KYGBgDQoNCiMjIDQuMyBTTUI6IERldGVybWluZSBzaXplIEJyZWFrcG9pbnRzDQpgYGB7cn0NCnNldG9yZGVyKEJSSUMubWFpbmRhdGEsRGF0ZSwtTVYuVVNELkp1bmUpDQpobHB2YXJpYWJsZSA8LSAgQlJJQy5tYWluZGF0YVttb250aD09NyAmICFpcy5uYShNVi5VU0QuSnVuZSksDQogICAgICAgICAgICAgICAgLihwZi5zaXplID0gaWZlbHNlKChjdW1zdW0oTVYuVVNELkp1bmUpL3N1bShNVi5VU0QuSnVuZSkpPj0wLjksIlNtYWxsIiwiQmlnIiksSWQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PXllYXJdDQoNCiMgTWVyZ2UgdGhlIHNpemUgcG9ydGZvbGlvIGFsbG9jYXRpb24gYmFjayBmcm9tIEp1bHkgWSB0byBKdW5lIFkrMQ0KQlJJQy5tYWluZGF0YSA8LSBtZXJnZShCUklDLm1haW5kYXRhLGhscHZhcmlhYmxlLA0KICAgICAgICAgICAgICAgICAgICAgICBieS54PWMoImhjanVuIiwiSWQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueT1jKCJ5ZWFyIiwiSWQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCg0KIyBkZWxldGUgTkEncyAob25seSBhYm91dCAxMDAwIHJvd3MpDQpCUklDLm1haW5kYXRhIDwtIG5hLm9taXQoQlJJQy5tYWluZGF0YSxjb2xzID0gInBmLnNpemUiKSANCmBgYA0KDQpSaVJGIHVzZWQgZm9yIGJlbmNobWFyayBpbiBwLjUwIGxlY3R1cmUgc2xpZGVzDQpGb3IgYW5udWFsaXNhdGlvbiB3ZSB1c2VkIGFyaXRobWV0aWMgYXZlcmFnZSAqIDEyDQoNCiMjIDQuNCBCZW5jaG1hcmsgKFZhbHVlIHdlaWdodGVkKQ0KDQpgYGB7cn0NCiMgY3JlYXRlIGNvcHkNCkJSSUMuYmVuY2htYXJrIDwtIEJSSUMubWFpbmRhdGENCg0KIyBmaWx0ZXIgb24gcGYuc2l6ZQ0KQlJJQy5iZW5jaG1hcmsgPC0gc3Vic2V0KEJSSUMuYmVuY2htYXJrLCBwZi5zaXplID09ICJCaWciICkNCg0KIyB2YWx1ZSB3ZWlnaHQgcmV0dXJucw0KIyMgY2FsY3VsYXRlIG1vbnRobHkgbWFya2V0IHZhbHVlIG92ZXIgYWxsIHN0b2Nrcw0KQlJJQy5iZW5jaG1hcmsudmFsdWVXZWlnaHRzIDwtIGFnZ3JlZ2F0ZShMTVYuVVNEIH4geW0sIGRhdGEgPSBCUklDLmJlbmNobWFyaywgRlVOID0gc3VtKQ0KY29sbmFtZXMoQlJJQy5iZW5jaG1hcmsudmFsdWVXZWlnaHRzKVsyXSA8LSAiVG90YWxWYWx1ZSINCg0KIyMgam9pbiB2YWx1ZSB3ZWlnaHRzIHRvIHN0b2Nrcw0KQlJJQy5iZW5jaG1hcmsgPC0gaW5uZXJfam9pbih4ID0gQlJJQy5iZW5jaG1hcmssIHkgPSBCUklDLmJlbmNobWFyay52YWx1ZVdlaWdodHMsIGJ5ID0gInltIikNCg0KIyMgY2FsY3VsYXRlIHZhbHVlIHdlaWdodA0KQlJJQy5iZW5jaG1hcmskVmFsdWVXZWlnaHQgPC0gQlJJQy5iZW5jaG1hcmskTE1WLlVTRC9CUklDLmJlbmNobWFyayRUb3RhbFZhbHVlDQoNCiMjIGNhbGN1bGF0ZSB2YWx1ZSB3ZWlnaHQgZXhjZXNzIHJldHVybiAvIHJldHVybg0KQlJJQy5iZW5jaG1hcmskd1JldCA8LSBCUklDLmJlbmNobWFyayRWYWx1ZVdlaWdodCpCUklDLmJlbmNobWFyayRSRVQuVVNEDQpCUklDLmJlbmNobWFyayR3RXhSZXQgPC0gQlJJQy5iZW5jaG1hcmskVmFsdWVXZWlnaHQgKiBCUklDLmJlbmNobWFyayRSaVJGDQoNCiMgcGVyIG1vbnRoDQpiZW5jaG1hcmsucmV0QnJpY00gPC0gYWdncmVnYXRlKGNiaW5kKHdSZXQsd0V4UmV0KSB+IHltICsgaGNqdW4sIGRhdGEgPSBCUklDLmJlbmNobWFyayxGVU4gPSBzdW0pDQoNCiMgcGVyIHllYXINCmJlbmNobWFyay5yZXRCcmljWSA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gaGNqdW4sIGRhdGEgPSBiZW5jaG1hcmsucmV0QnJpY00sRlVOID0gbWVhbikNCg0KIyMgYW5udWFsaXNlDQpiZW5jaG1hcmsucmV0QnJpY1kkd1JldCA8LSBiZW5jaG1hcmsucmV0QnJpY1kkd1JldCoxMg0KYmVuY2htYXJrLnJldEJyaWNZJHdFeFJldCA8LSBiZW5jaG1hcmsucmV0QnJpY1kkd0V4UmV0KjEyDQoNCiMgcGVyIGNvdW50cnkNCmJlbmNobWFyay5yZXRDb3VudHJ5TSA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gY291bnRyeS54ICsgeW0gKyBoY2p1biwgZGF0YSA9IEJSSUMuYmVuY2htYXJrLEZVTiA9IHN1bSkNCg0KIyBwZXIgeWVhcg0KYmVuY2htYXJrLnJldENvdW50cnlZIDwtIGFnZ3JlZ2F0ZShjYmluZCh3UmV0LHdFeFJldCkgfiBjb3VudHJ5LnggKyBoY2p1biwgZGF0YSA9IGJlbmNobWFyay5yZXRDb3VudHJ5TSxGVU4gPSBtZWFuKQ0KDQojIyBhbm51YWxpc2UNCmJlbmNobWFyay5yZXRDb3VudHJ5WSR3UmV0IDwtIGJlbmNobWFyay5yZXRDb3VudHJ5WSR3UmV0KjEyDQpiZW5jaG1hcmsucmV0Q291bnRyeVkkd0V4UmV0IDwtIGJlbmNobWFyay5yZXRDb3VudHJ5WSR3RXhSZXQqMTINCg0KIyBzaW5nbGUgZGF0YWZyYW1lDQpiZW5jaG1hcmtfQlJJQyA8LSBpbm5lcl9qb2luKGJlbmNobWFyay5yZXRCcmljWSxiZW5jaG1hcmsucmV0QnJpY00sYnkgPSAiaGNqdW4iKQ0KYmVuY2htYXJrX0NvdW50cnkgPC0gaW5uZXJfam9pbihiZW5jaG1hcmsucmV0Q291bnRyeVksYmVuY2htYXJrLnJldENvdW50cnlNLGJ5ID0gYygiaGNqdW4iLCJjb3VudHJ5LngiKSkNCiMgcmVuYW1lIGNvbHVtbnMNCmNvbG5hbWVzKGJlbmNobWFya19CUklDKVsyXSA8LSAiWWVhcmx5UmV0dXJuIg0KY29sbmFtZXMoYmVuY2htYXJrX0JSSUMpWzNdIDwtICJZZWFybHlFeGNlc3NSZXR1cm4iDQpjb2xuYW1lcyhiZW5jaG1hcmtfQlJJQylbNV0gPC0gIk1vbnRobHlSZXR1cm4iDQpjb2xuYW1lcyhiZW5jaG1hcmtfQlJJQylbNl0gPC0gIk1vbnRobHlFeGNlc3NSZXR1cm4iDQoNCmNvbG5hbWVzKGJlbmNobWFya19Db3VudHJ5KVszXSA8LSAiWWVhcmx5UmV0dXJuIg0KY29sbmFtZXMoYmVuY2htYXJrX0NvdW50cnkpWzRdIDwtICJZZWFybHlFeGNlc3NSZXR1cm4iDQpjb2xuYW1lcyhiZW5jaG1hcmtfQ291bnRyeSlbNl0gPC0gIk1vbnRobHlSZXR1cm4iDQpjb2xuYW1lcyhiZW5jaG1hcmtfQ291bnRyeSlbN10gPC0gIk1vbnRobHlFeGNlc3NSZXR1cm4iDQpgYGANCiMjIDQuNSBNYXJrZXQgKEV4Y2VzcykgUmV0dXJuDQpgYGB7cn0NCiMgY3JlYXRlIGNvcHkNCkJSSUMubWFya2V0IDwtIEJSSUMubWFpbmRhdGENCg0KIyB2YWx1ZSB3ZWlnaHQgcmV0dXJucw0KIyMgY2FsY3VsYXRlIG1vbnRobHkgbWFya2V0IHZhbHVlIG92ZXIgYWxsIHN0b2Nrcw0KQlJJQy5tYXJrZXQudmFsdWVXZWlnaHRzIDwtIGFnZ3JlZ2F0ZShMTVYuVVNEIH4geW0sIGRhdGEgPSBCUklDLm1hcmtldCwgRlVOID0gc3VtKQ0KY29sbmFtZXMoQlJJQy5tYXJrZXQudmFsdWVXZWlnaHRzKVsyXSA8LSAiVG90YWxWYWx1ZSINCg0KIyMgam9pbiB2YWx1ZSB3ZWlnaHRzIHRvIHN0b2Nrcw0KQlJJQy5tYXJrZXQgPC0gaW5uZXJfam9pbih4ID0gQlJJQy5tYXJrZXQsIHkgPSBCUklDLm1hcmtldC52YWx1ZVdlaWdodHMsIGJ5ID0gInltIikNCg0KIyMgY2FsY3VsYXRlIHZhbHVlIHdlaWdodA0KQlJJQy5tYXJrZXQkVmFsdWVXZWlnaHQgPC0gQlJJQy5tYXJrZXQkTE1WLlVTRC9CUklDLm1hcmtldCRUb3RhbFZhbHVlDQoNCiMjIGNhbGN1bGF0ZSB2YWx1ZSB3ZWlnaHQgZXhjZXNzIHJldHVybiAvIHJldHVybg0KQlJJQy5tYXJrZXQkd1JldCA8LSBCUklDLm1hcmtldCRWYWx1ZVdlaWdodCpCUklDLm1hcmtldCRSRVQuVVNEDQpCUklDLm1hcmtldCR3RXhSZXQgPC0gQlJJQy5tYXJrZXQkVmFsdWVXZWlnaHQgKiBCUklDLm1hcmtldCRSaVJGDQoNCiMgcGVyIG1vbnRoDQptYXJrZXQucmV0QnJpY00gPC0gYWdncmVnYXRlKGNiaW5kKHdSZXQsd0V4UmV0KSB+IHltICsgaGNqdW4sIGRhdGEgPSBCUklDLm1hcmtldCxGVU4gPSBzdW0pDQoNCiMgcGVyIHllYXINCm1hcmtldC5yZXRCcmljWSA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gaGNqdW4sIGRhdGEgPSBtYXJrZXQucmV0QnJpY00sRlVOID0gbWVhbikNCg0KIyMgYW5udWFsaXNlDQptYXJrZXQucmV0QnJpY1kkd1JldCA8LSBtYXJrZXQucmV0QnJpY1kkd1JldCoxMg0KbWFya2V0LnJldEJyaWNZJHdFeFJldCA8LSBtYXJrZXQucmV0QnJpY1kkd0V4UmV0KjEyDQoNCiMgcGVyIGNvdW50cnkNCm1hcmtldC5yZXRDb3VudHJ5TSA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gY291bnRyeS54ICsgeW0gKyBoY2p1biwgZGF0YSA9IEJSSUMubWFya2V0LEZVTiA9IHN1bSkNCg0KIyBwZXIgeWVhcg0KbWFya2V0LnJldENvdW50cnlZIDwtIGFnZ3JlZ2F0ZShjYmluZCh3UmV0LHdFeFJldCkgfiBjb3VudHJ5LnggKyBoY2p1biwgZGF0YSA9IG1hcmtldC5yZXRDb3VudHJ5TSxGVU4gPSBtZWFuKQ0KDQojIyBhbm51YWxpc2UNCm1hcmtldC5yZXRDb3VudHJ5WSR3UmV0IDwtIG1hcmtldC5yZXRDb3VudHJ5WSR3UmV0KjEyDQptYXJrZXQucmV0Q291bnRyeVkkd0V4UmV0IDwtIG1hcmtldC5yZXRDb3VudHJ5WSR3RXhSZXQqMTINCg0KIyBzaW5nbGUgZGF0YWZyYW1lDQptYXJrZXRfQlJJQyA8LSBpbm5lcl9qb2luKG1hcmtldC5yZXRCcmljWSxtYXJrZXQucmV0QnJpY00sYnkgPSAiaGNqdW4iKQ0KbWFya2V0X0NvdW50cnkgPC0gaW5uZXJfam9pbihtYXJrZXQucmV0Q291bnRyeVksbWFya2V0LnJldENvdW50cnlNLGJ5ID0gYygiaGNqdW4iLCJjb3VudHJ5LngiKSkNCiMgcmVuYW1lIGNvbHVtbnMNCmNvbG5hbWVzKG1hcmtldF9CUklDKVsyXSA8LSAiWWVhcmx5UmV0dXJuIg0KY29sbmFtZXMobWFya2V0X0JSSUMpWzNdIDwtICJZZWFybHlFeGNlc3NSZXR1cm4iDQpjb2xuYW1lcyhtYXJrZXRfQlJJQylbNV0gPC0gIk1vbnRobHlSZXR1cm4iDQpjb2xuYW1lcyhtYXJrZXRfQlJJQylbNl0gPC0gIk1vbnRobHlFeGNlc3NSZXR1cm4iDQoNCmNvbG5hbWVzKG1hcmtldF9Db3VudHJ5KVszXSA8LSAiWWVhcmx5UmV0dXJuIg0KY29sbmFtZXMobWFya2V0X0NvdW50cnkpWzRdIDwtICJZZWFybHlFeGNlc3NSZXR1cm4iDQpjb2xuYW1lcyhtYXJrZXRfQ291bnRyeSlbNl0gPC0gIk1vbnRobHlSZXR1cm4iDQpjb2xuYW1lcyhtYXJrZXRfQ291bnRyeSlbN10gPC0gIk1vbnRobHlFeGNlc3NSZXR1cm4iDQpgYGANCg0KIEJyZWFrcG9pbnRzIGZvciBSTVcgYW5kIENNQSBhcmUgYmFzZWQgb24gSmlhbygyMDE3KSBhbmQgRkYoMjAxNSkgMngzIHNvcnQgPSBOWVNFIFBlcmNlbnRpbGVzIChGRigyMDE1KSBwLjYpDQohW1BvcnRmb2xpb1NvcnRzLl0gKCJJbWFnZXMvUG9ydGZvbGlvU29ydHMuanBnIikNCiMjIDQuNiAtIDQuOCBEZXRlcm1pbmUgb3RoZXIgYnJlYWtwb2ludHMNCmBgYHtyfQ0KDQojIDQuNiBITUw6IERldGVybWluZSBCL00gYnJlYWtwb2ludHMgLS0tLQ0KDQojIEJyZWFrcG9pbnRzIGZvciBSTVcgYW5kIENNQSBhcmUgYmFzZWQgb24gSmlhbygyMDE3KSBhbmQgRkYoMjAxNSkgMngzIHNvcnQgPSBOWVNFIFBlcmNlbnRpbGVzIChGRigyMDE1KSBwLjYpDQojIVtQb3J0Zm9saW9Tb3J0cy5dICgiSW1hZ2VzL1BvcnRmb2xpb1NvcnRzLmpwZyIpDQoNCiMgRGV0ZXJtaW5lIHRoZSBCL00gYnJlYWtwb2ludHMgYmFzZWQgb24gYmlnIHN0b2NrcyBvbmx5DQpobHB2YXJpYWJsZTIgPC0gQlJJQy5tYWluZGF0YVttb250aD09NyAmICFpcy5uYShCTSkgJiBwZi5zaXplPT0iQmlnIiwgLihibV9iYjMwID0gcXVhbnRpbGUoQk0gLCBwcm9icyA9IGMoMC4zKSwgbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibV9iYjcwID0gcXVhbnRpbGUoQk0gLCBwcm9icyA9IGMoMC43KSwgbmEucm09VCkpLGJ5PXllYXJdDQogICAgICAgICAgICAgIA0KIyBNZXJnZSB0aGUgQi9NIHBvcnRmb2xpbyBhbGxvY2F0aW9uIGJhY2sgZnJvbSBKdWx5IFkgdG8gSnVuZSBZKzENCkJSSUMubWFpbmRhdGEgPC0gbWVyZ2UoQlJJQy5tYWluZGF0YSxobHB2YXJpYWJsZTIsDQogICAgICAgICAgICAgICAgICAgICAgIGJ5Lng9YygiaGNqdW4iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueT1jKCJ5ZWFyIiksDQogICAgICAgICAgICAgICAgICAgICAgIGFsbC54PVQpDQoNCkJSSUMubWFpbmRhdGFbICwgcGYuYm0gOj0gaWZlbHNlKEJNPmJtX2JiNzAsIkhpZ2giLGlmZWxzZSgoQk08PWJtX2JiNzAgJiBCTT5ibV9iYjMwKSwiTmV1dHJhbCIsaWZlbHNlKEJNPD1ibV9iYjMwLCJMb3ciLE5BKSkpXQ0KDQpCUklDLm1haW5kYXRhWywgU0laRV9WQUxVRSA6PSBwYXN0ZTAocGYuc2l6ZSwiLiIscGYuYm0pXQ0KDQojIDQuNyBSTVc6IERldGVybWluZSBPUC9CRSBicmVha3BvaW50cyAtLS0tDQoNCiMgRGV0ZXJtaW5lIHRoZSBPUC9CRSBicmVha3BvaW50cyBiYXNlZCBvbiBiaWcgc3RvY2tzIG9ubHkNCmhscHZhcmlhYmxlMiA8LSBCUklDLm1haW5kYXRhW21vbnRoPT03ICYgIWlzLm5hKE9QQkUpICYgcGYuc2l6ZT09IkJpZyIsIC4ob3BiZV9iYjMwID0gcXVhbnRpbGUoT1BCRSAsIHByb2JzID0gYygwLjMpLCBuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wYmVfYmI3MCA9IHF1YW50aWxlKE9QQkUgLCBwcm9icyA9IGMoMC43KSwgbmEucm09VCkpLGJ5PXllYXJdDQogICAgICAgICAgICAgIA0KIyBNZXJnZSB0aGUgT1AvQkUgcG9ydGZvbGlvIGFsbG9jYXRpb24gYmFjayBmcm9tIEp1bHkgWSB0byBKdW5lIFkrMQ0KQlJJQy5tYWluZGF0YSA8LSBtZXJnZShCUklDLm1haW5kYXRhLGhscHZhcmlhYmxlMiwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueD1jKCJoY2p1biIpLA0KICAgICAgICAgICAgICAgICAgICAgICBieS55PWMoInllYXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCg0KIyAzIE9QL0JFIGJyYWNrZXRzOiBSb2J1c3QsIE5ldXRyYWwgYW5kIFdlYWsNCkJSSUMubWFpbmRhdGFbICwgcGYub3BiZSA6PSBpZmVsc2UoT1BCRT5vcGJlX2JiNzAsIlJvYnVzdCIsaWZlbHNlKChPUEJFPD1vcGJlX2JiNzAgJiBPUEJFPm9wYmVfYmIzMCksIk5ldXRyYWwiLGlmZWxzZShPUEJFPD1vcGJlX2JiMzAsIldlYWsiLE5BKSkpXQ0KDQpCUklDLm1haW5kYXRhWywgU0laRV9QUk9GSVRBQklMSVRZIDo9IHBhc3RlMChwZi5zaXplLCIuIixwZi5vcGJlKV0NCg0KIyA0LjggQ01BOiBEZXRlcm1pbmUgQXNzZXQgQ2hhbmdlIEJyZWFrcG9pbnRzIC0tLS0NCg0KI2ludmVzdG1lbnQ6IEFzIGluIENvb3BlciBldCBhbC4gKDIwMDgpLCB3ZSBtZWFzdXJlIGFzc2V0IGdyb3d0aCBpbiBKdW5lIG9mIHllYXIgeSBhcyB0aGUgcGVyY2VudGFnZSBjaGFuZ2UgaW4gdG90YWwgYXNzZXRzIChXQzAyOTk5KSBmcm9tIGZpc2NhbCB5ZWFyIGVuZGluZyBpbiBjYWxlbmRhciB5ZWFyIHniiJIyIHRvIGZpc2NhbCB5ZWFyIGVuZGluZyBpbiBjYWxlbmRhciB5ZWFyIHniiJIxLg0KDQojIERldGVybWluZSB0aGUgQUMgYnJlYWtwb2ludHMgYmFzZWQgb24gYmlnIHN0b2NrcyBvbmx5DQpobHB2YXJpYWJsZTIgPC0gQlJJQy5tYWluZGF0YVttb250aD09NyAmICFpcy5uYShBc3NldENoYW5nZSkgJiBwZi5zaXplPT0iQmlnIiwgLihhY19iYjMwID0gcXVhbnRpbGUoQXNzZXRDaGFuZ2UgLCBwcm9icyA9IGMoMC4zKSwgbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY19iYjcwID0gcXVhbnRpbGUoQXNzZXRDaGFuZ2UgLCBwcm9icyA9IGMoMC43KSwgbmEucm09VCkpLGJ5PXllYXJdDQogICAgICAgICAgICAgIA0KIyBNZXJnZSB0aGUgQUMgcG9ydGZvbGlvIGFsbG9jYXRpb24gYmFjayBmcm9tIEp1bHkgWSB0byBKdW5lIFkrMQ0KQlJJQy5tYWluZGF0YSA8LSBtZXJnZShCUklDLm1haW5kYXRhLGhscHZhcmlhYmxlMiwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueD1jKCJoY2p1biIpLA0KICAgICAgICAgICAgICAgICAgICAgICBieS55PWMoInllYXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCg0KIyAzIGludmVzdG1lbnQgYnJhY2tldHM6IEFnZ3Jlc3NpdmUsIG5ldXRyYWwgYW5kIGNvbnNlcnZhdGl2ZQ0KQlJJQy5tYWluZGF0YVsgLCBwZi5hYyA6PSBpZmVsc2UoQXNzZXRDaGFuZ2U+YWNfYmI3MCwiQWdncmVzc2l2ZSIsaWZlbHNlKChBc3NldENoYW5nZTw9YWNfYmI3MCAmIEFzc2V0Q2hhbmdlPmFjX2JiMzApLCJOZXV0cmFsIixpZmVsc2UoQXNzZXRDaGFuZ2U8PWFjX2JiMzAsIkNvbnNlcnZhdGl2ZSIsTkEpKSldDQoNCkJSSUMubWFpbmRhdGFbLCBTSVpFX0lOVkVTVE1FTlQgOj0gcGFzdGUwKHBmLnNpemUsIi4iLHBmLmFjKV0NCmBgYA0KDQoNCmh0dHBzOi8vbWJhLnR1Y2suZGFydG1vdXRoLmVkdS9wYWdlcy9mYWN1bHR5L2tlbi5mcmVuY2gvRGF0YV9MaWJyYXJ5L2YtZl81X2ZhY3RvcnNfMngzLmh0bWwNCg0KIyM0LjkgQ2FsY3VsYXRlIEZhY3RvcnMNCmBgYHtyfQ0KIyBITUwgLS0tLQ0KcG9ydGZvbGlvX2htbCA8LSBCUklDLm1haW5kYXRhWyFpcy5uYShwZi5zaXplKSAmICFpcy5uYShwZi5ibSldICU+JSAjIHRoaXMgb3BlcmF0b3IgbmVzdHMgZnVuY3Rpb25zDQogIGdyb3VwX2J5KHltLFNJWkVfVkFMVUUpICU+JSAjIGRvICJldmVyeXRoaW5nIiBmb3IgdGhlIGdyb3VwcyBzcGVjaWZpZWQgaGVyZQ0KICBzdW1tYXJpemUocmV0LnBvcnQgPSB3ZWlnaHRlZC5tZWFuKFJFVC5VU0QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTE1WLlVTRCkpICU+JSAjIHZ3IHJldHVybnMgdXNpbmcgbGFnZ2VkIG1jYXANCiAgc3ByZWFkKFNJWkVfVkFMVUUscmV0LnBvcnQpICU+JSAjIGNyZWF0ZSBvbmUgY29sdW1uIGZvciBlYWNoIGdyb3VwDQogIG11dGF0ZSgNCiAgICBTbWFsbCA9IChTbWFsbC5IaWdoICsgU21hbGwuTmV1dHJhbCArIFNtYWxsLkxvdykvMywgIyBqdXN0IGV4ZW1wbGFyeQ0KICAgIEJpZyA9IChCaWcuSGlnaCArIEJpZy5OZXV0cmFsICsgQmlnLkxvdykvMywNCiAgICBTTUJfSE1MID0gU21hbGwtQmlnLA0KICAgIEhpZ2ggPSAoU21hbGwuSGlnaCArIEJpZy5IaWdoKS8yLA0KICAgIExvdyA9IChTbWFsbC5Mb3cgKyBCaWcuTG93KS8yLA0KICAgIEhNTCA9IEhpZ2gtTG93DQogICkNCg0KcG9ydGZvbGlvX2htbCA8LSBhcy5kYXRhLnRhYmxlKHBvcnRmb2xpb19obWwpDQoNCiMgUk1XIC0tLS0NCnBvcnRmb2xpb19ybXcgPC0gQlJJQy5tYWluZGF0YVshaXMubmEocGYuc2l6ZSkgJiAhaXMubmEocGYub3BiZSldICU+JSAjIHRoaXMgb3BlcmF0b3IgbmVzdHMgZnVuY3Rpb25zDQogIGdyb3VwX2J5KHltLFNJWkVfUFJPRklUQUJJTElUWSkgJT4lICMgZG8gImV2ZXJ5dGhpbmciIGZvciB0aGUgZ3JvdXBzIHNwZWNpZmllZCBoZXJlDQogIHN1bW1hcml6ZShyZXQucG9ydCA9IHdlaWdodGVkLm1lYW4oUkVULlVTRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMTVYuVVNEKSkgJT4lICMgdncgcmV0dXJucyB1c2luZyBsYWdnZWQgbWNhcA0KICBzcHJlYWQoU0laRV9QUk9GSVRBQklMSVRZLHJldC5wb3J0KSAlPiUgIyBjcmVhdGUgb25lIGNvbHVtbiBmb3IgZWFjaCBncm91cA0KICBtdXRhdGUoDQogICAgU21hbGwgPSAoU21hbGwuUm9idXN0ICsgU21hbGwuTmV1dHJhbCArIFNtYWxsLldlYWspLzMsICMganVzdCBleGVtcGxhcnkNCiAgICBCaWcgPSAoQmlnLlJvYnVzdCArIEJpZy5OZXV0cmFsICsgQmlnLldlYWspLzMsDQogICAgU01CX1JNVyA9IFNtYWxsLUJpZywNCiAgICBSb2J1c3QgPSAoU21hbGwuUm9idXN0ICsgQmlnLlJvYnVzdCkvMiwNCiAgICBXZWFrID0gKFNtYWxsLldlYWsgKyBCaWcuV2VhaykvMiwNCiAgICBSTVcgPSBSb2J1c3QgLSBXZWFrDQogICkNCg0KcG9ydGZvbGlvX3JtdyA8LSBhcy5kYXRhLnRhYmxlKHBvcnRmb2xpb19ybXcpDQoNCiMgQ01BIC0tLS0NCnBvcnRmb2xpb19jbWEgPC0gQlJJQy5tYWluZGF0YVshaXMubmEocGYuc2l6ZSkgJiAhaXMubmEocGYuYWMpXSAlPiUgIyB0aGlzIG9wZXJhdG9yIG5lc3RzIGZ1bmN0aW9ucw0KICBncm91cF9ieSh5bSxTSVpFX0lOVkVTVE1FTlQpICU+JSAjIGRvICJldmVyeXRoaW5nIiBmb3IgdGhlIGdyb3VwcyBzcGVjaWZpZWQgaGVyZQ0KICBzdW1tYXJpemUocmV0LnBvcnQgPSB3ZWlnaHRlZC5tZWFuKFJFVC5VU0QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTE1WLlVTRCkpICU+JSAjIHZ3IHJldHVybnMgdXNpbmcgbGFnZ2VkIG1jYXANCiAgc3ByZWFkKFNJWkVfSU5WRVNUTUVOVCxyZXQucG9ydCkgJT4lICMgY3JlYXRlIG9uZSBjb2x1bW4gZm9yIGVhY2ggZ3JvdXANCiAgbXV0YXRlKA0KICAgIFNtYWxsID0gKFNtYWxsLkFnZ3Jlc3NpdmUgKyBTbWFsbC5OZXV0cmFsICsgU21hbGwuQ29uc2VydmF0aXZlKS8zLCAjIGp1c3QgZXhlbXBsYXJ5DQogICAgQmlnID0gKEJpZy5BZ2dyZXNzaXZlICsgQmlnLk5ldXRyYWwgKyBCaWcuQ29uc2VydmF0aXZlKS8zLA0KICAgIFNNQl9DTUEgPSBTbWFsbC1CaWcsDQogICAgQWdncmVzc2l2ZSA9IChTbWFsbC5BZ2dyZXNzaXZlICsgQmlnLkFnZ3Jlc3NpdmUpLzIsDQogICAgQ29uc2VydmF0aXZlID0gKFNtYWxsLkNvbnNlcnZhdGl2ZSArIEJpZy5Db25zZXJ2YXRpdmUpLzIsDQogICAgQ01BID0gQ29uc2VydmF0aXZlIC0gQWdncmVzc2l2ZQ0KICApDQoNCnBvcnRmb2xpb19jbWEgPC0gYXMuZGF0YS50YWJsZShwb3J0Zm9saW9fY21hKQ0KDQojIE1PTSAtLS0tDQpwb3J0Zm9saW9fbW9tIDwtIEJSSUMubWFpbmRhdGFbIWlzLm5hKHBmLm1vbWVudHVtKV0gJT4lIA0KICBncm91cF9ieSh5bSxwZi5tb21lbnR1bSkgJT4lIA0KICBzdW1tYXJpemUocmV0LnBvcnQgPSB3ZWlnaHRlZC5tZWFuKFJFVC5VU0QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTE1WLlVTRCkpICU+JSANCiAgc3ByZWFkKHBmLm1vbWVudHVtLHJldC5wb3J0KSAlPiUgDQogIG11dGF0ZSgNCiAgICBNT00gPSBXaW5uZXIgLSBMb29zZXINCiAgKQ0KcG9ydGZvbGlvX21vbSA8LSBhcy5kYXRhLnRhYmxlKHBvcnRmb2xpb19tb20pDQoNCg0KZmFjdG9ycyA8LSBpbm5lcl9qb2luKHggPSBwb3J0Zm9saW9faG1sLCB5ID0gcG9ydGZvbGlvX3JtdywgYnkgPSAieW0iKQ0KZmFjdG9ycyA8LSBpbm5lcl9qb2luKHggPSBmYWN0b3JzLCB5ID0gcG9ydGZvbGlvX2NtYSwgYnkgPSAieW0iKQ0KZmFjdG9ycyA8LSBpbm5lcl9qb2luKHggPSBmYWN0b3JzLCB5ID0gcG9ydGZvbGlvX21vbSwgYnkgPSAieW0iKQ0KZmFjdG9ycyA8LSBzdWJzZXQoZmFjdG9ycywgc2VsZWN0ID0gYygieW0iLCJDTUEiLCJITUwiLCJSTVciLCJTTUJfSE1MIiwiU01CX1JNVyIsIlNNQl9DTUEiLCJNT00iKSkNCmZhY3RvcnMkU01CIDwtICgoZmFjdG9ycyRTTUJfSE1MICsgZmFjdG9ycyRTTUJfUk1XICsgZmFjdG9ycyRTTUJfQ01BKS8zKQ0KZmFjdG9ycyA8LSBzdWJzZXQoZmFjdG9ycywgc2VsZWN0ID0gYygieW0iLCJDTUEiLCJITUwiLCJSTVciLCJTTUIiLCJNT00iKSkNCg0Kc3VtbWFyeShmYWN0b3JzKQ0KDQoNCnN1bW1hcnkoQlJJQy5tYWluZGF0YSRCTSkNCmBgYA0KDQoNCklTSU46IEludGVybmF0aW9uYWwgU2VjdXJpdHkgSWRlbnRpZmljYXRpb24gTnVtYmVyIChzdG9jayBpZGVudGlmaWVyKQ0KRVNUQVQ6IGFjdGl2ZSB2cyBpbmFjdGl2ZSBjb21wYW55IChwdWJsaWNseSBsaXN0ZWQgb3Igbm90KQ0KSWQ6IGpvaW4gY29sdW1uIHdpdGggQlJJQy55ZWFybHkgZGF0YWZyYW1lDQpJTkRNOiBpbmR1c3RyeSBzZWN0b3IgY29kZQ0KDQpHRU9HTjogZ2VvZ3JhcGhpYyBncm91cCBuYW1lDQpHRU9MTjogZ2VvZ3JhcGhpYyBsb2NhdGlvbg0KDQpMaXN0IG9mIERhdGFiYXNlIGNvZGVzOg0KaHR0cHM6Ly93d3cuYndsLnVuaS1tYW5uaGVpbS5kZS9tZWRpYS9MZWhyc3R1ZWhsZS9id2wvTWF1Zy9EYXRhYmFzZV9pbmZvL0RhdGFzdHJlYW1fZGF0YXlwZXMucGRmDQoNCklEOiA/Pw0KQ291bnRyeTogNCBCUklDIENPVU5UUlkgQ09ERVMNCklDQlNVQzogaW5kdXN0cmlhbCBjbGFzc2lmaWNhdGlvbiBiZW5jaG1hcmsNCmh0dHBzOi8vbGluay5zcHJpbmdlci5jb20vY29udGVudC9wZGYvYmJtJTNBOTc4LTMtODM1MC05NTMxLTElMkYxLnBkZg0KDQpXQzA3MDIxOiBTSUMoc3RhbmRhcmQgaW5kdXN0cmlhbCBjbGFzc2lmaWNhdGlvbikgcHJpbWFyeSBjb2RlIGZyb20gV29ybGRzY29wZQ0KVzA1NjUxOiBDb21tb24gU2hhcmVzIFRyYWRlZCAtIEFubnVhbCAoU2VjdXJpdHkpDQoNCg0KKlRPIERPJ3MqOg0KDQotIENhbGN1bGF0ZSBCZW5jaG1hcmsgKG1hcmtldC1jYXAgd2VpZ2h0ZWQgYmlnIHN0b2NrcyBvZiB0aGUgQlJJQyByZWdpb24pIHx8IERPTkUNCi0gQ2FsY3VsYXRlIGJyZWFrIHBvaW50cyBvbiBiaWcgc3RvY2tzIHx8IERPTkUNCi0gZGVjaWRlIG9uIHN0cmF0ZWd5IGFuZCBpbXBsZW1lbnQgaXQgfHwgV09SS0lORw0KLSBjYWxjdWxhdGUgcG9ydGZvbGlvIGNoYXJhY3RlcmlzdGljcyANCi0gdmlzdWFsaXplIGFuZCBzaG93Y2FzZSBzdHJhdGVneSBwZXJmb3JtYW5jZQ0KLSByZWdyZXNzIHN0cmF0ZWd5IFBGIG9uIEZGNUZNIGFuZCBtb21lbnR1bSBmb3Igc3R5bGUgZXhwb3N1cmUgYW5hbHlzaXMNCi0gTGl0ZXJhdHVyZSB8fCBXSVANCi0gc29ydGluZyBBLXNoYXJlcyAuLi4gaG93IHRvIGlkZW50aWZ5IHRoZW0/IHx8IERPTkUNCg0KDQoqUHJvamVjdCBEYXRlcyo6DQpUaGVzaXMgc3VibWlzc2lvbjogSnVuZSAyMQ0KRmluYWwgcHJlc2VudGF0aW9uOiBKdW5lIDA3DQoNCipTdHJhdGVneSo6DQpHRFAgd2VpZ2h0ZWQgY291bnRyaWVzOyBzdG9jayBsZXZlbDogbWF4IHNoYXJwZSByYXRpbywgbWluIHZvbGF0aWxpdHksIGVxdWFsIHNlY3RvciB3ZWlnaHRzIG9yIHF1b3RhcywgbW9tZW50dW0/DQoNCkVEQQ0KDQpUbyBETzogY29tcHV0ZSBjb3JyZWxhdGlvbnMgYnkgc2VjdG9yICgxMCBzZWN0b3JzKQ0KDQpgYGB7cn0NCiMgcmVndWxhciBjb3JyZWxhdGlvbiBtYXRyaXggb2YgYWxsIChmb3VyKSBudW1lcmljIGF0dHJpYnV0ZXMNCmNvcihzZWxlY3QoQlJJQy5zdGF0aWMsIHdoZXJlKGlzLm51bWVyaWMpKSkNCmBgYA0KDQoqKlNvbWUgY29udmVudGlvbnM6KioNCg0KQ2hhcmFjdGVyaXN0aWMgc2hvdWxkIGJlIGNhbGN1bGF0ZWQgYXMgaW4gSGFuYXVlciAmIExhdXRlcmJhY2ggKDIwMTkpIG9yIGluIEhhbmF1ZXIgKDIwMjApDQoNCkJpZyBzdG9ja3Mgc2hvdWxkIGJlIGRlZmluZWQgYXMgdGhlIGJpZ2dlc3Qgc3RvY2tzIHdoaWNoIHRvZ2V0aGVyIGFjY291bnQgZm9yIDkwJSBvZiBhDQpjb3VudHJ5J3MgYWdncmVnYXRlZCBtYXJrZXQgY2FwaXRhbGl6YXRpb24NCkJlbmNobWFyayBzaG91bGQgYmUgZGVmaW5lZCBhcyB0aGUgY2FwLXdlaWdodGVkIHVuaXZlcnNlIG9mIGJpZyBzdG9ja3MNClJldHVybnMgc2hvdWxkIGJlIGluIFVTRA0KQnJlYWtwb2ludHMgKGZvciBGYW1hLUZyZW5jaCBmYWN0b3JzKSBzaG91bGQgYmUgY2FsY3VsYXRlZCBvbiBiaWcgc3RvY2tzIChhcyBpbiB0aGUNCmV4Y3Vyc3VzKSBidXQgYm90aCBzbWFsbCBhbmQgYmlnIHN0b2NrcyBnbyBpbnRvIHRoZSBmYWN0b3IgY2FsY3VsYXRpb24uDQoNCg0KDQoNCiM1LlNUUkFURUdZIC0gTXVsdGlmYWN0b3IgUG9ydGZvbGlvIHNvcnQNCk1vbWVudHVtIHNvcnRpbmcgaXMgZG9uZSBkdXJpbmcgIzIuDQojIzUuMSBWYWx1ZSBCcmVha3BvaW50cw0KYGBge3J9DQpCUklDLnN0cmF0ZWd5IDwtIEJSSUMubWFpbmRhdGENCg0KY29sbmFtZXMoQlJJQy5zdHJhdGVneSkNCg0KIyMgVmFsdWUgZmFjdG9yDQojIyBjcmVhdGluZyBhIGxhcmdlIGNhcCBhbmQgaGlnaCBCL00gcmF0aW8gY29sdW1uIChsYXJnZSBjYXAgdmFsdWUpDQoNCiMgc3Vic2V0dGluZyB0aGUgbGFyZ2UgY2FwIHN0b2NrcyBvbmx5IChyZWJhbGFuY2VkIHllYXJseSkNCkJSSUMuc3RyYXRlZ3kgPC0gc3Vic2V0KEJSSUMuc3RyYXRlZ3ksIHBmLnNpemUgPT0gIkJpZyIgKQ0KDQojIHN1YnNldHRpbmcgb25seSB2YWx1ZSBzdG9ja3MgKGN1dG9mZiA9IG1lZGlhbikgTG9vayB1cCBDVVRPRkYgZGV0YWlscw0KIyBEZXRlcm1pbmUgdGhlIHZhbHVlIGJyZWFrcG9pbnRzDQpobHB2YXJpYWJsZTIgPC0gQlJJQy5tYWluZGF0YVttb250aD09NywgLihtZWRpYW4gPSBxdWFudGlsZShCTSAsIHByb2JzID0gYygwLjUpLCBuYS5ybT1UKSksYnk9eWVhcl0NCiAgICAgICAgICAgICAgDQojIE1lcmdlIHRoZSB2YWx1ZSBwb3J0Zm9saW8gYWxsb2NhdGlvbiBiYWNrIGZyb20gSnVseSBZIHRvIEp1bmUgWSsxDQpCUklDLnN0cmF0ZWd5IDwtIG1lcmdlKEJSSUMuc3RyYXRlZ3ksaGxwdmFyaWFibGUyLA0KICAgICAgICAgICAgICAgICAgICAgICBieS54PWMoImhjanVuIiksDQogICAgICAgICAgICAgICAgICAgICAgIGJ5Lnk9YygieWVhciIpLA0KICAgICAgICAgICAgICAgICAgICAgICBhbGwueD1UKQ0KDQpCUklDLnN0cmF0ZWd5WyAsIHBmLnZhbHVlIDo9IGlmZWxzZShCTT5tZWRpYW4sIlZhbHVlIiwoaWZlbHNlKEJNPD1tZWRpYW4sIkdyb3d0aCIsTkEpKSldDQoNCnRhYmxlKEJSSUMuc3RyYXRlZ3kkcGYudmFsdWUpDQpkaW0oQlJJQy5zdHJhdGVneSkNCmBgYA0KDQojIzUuMiBMb3cgVm9sDQpTdHJhdGVneSBpbXBsZW1lbnRhdGlvbiBvbiB0aGUgYmFsYW5jZWQgcGFuZWwgZGF0YSAoTXVsdGlmYWN0b3IgZXRmKQ0KYGBge3J9DQoNCiMgRGV0ZXJtaW5lIHRoZSBsb3dfdm9sIGJyZWFrcG9pbnRzIGJhc2VkIG9uIGJpZyBzdG9ja3Mgb25seQ0KaGxwdmFyaWFibGUyIDwtIEJSSUMuc3RyYXRlZ3lbbW9udGg9PTcsIC4obG93ZXJfMjAgPSBxdWFudGlsZSh2b2xhdGlsaXR5ICwgcHJvYnMgPSBjKDAuMiksIG5hLnJtPVQpKSxieT15ZWFyXQ0KICAgICAgICAgICAgICANCiMgTWVyZ2UgdGhlIGxvd192b2wgcG9ydGZvbGlvIGFsbG9jYXRpb24gYmFjayBmcm9tIEp1bHkgWSB0byBKdW5lIFkrMQ0KQlJJQy5zdHJhdGVneSA8LSBtZXJnZShCUklDLnN0cmF0ZWd5LGhscHZhcmlhYmxlMiwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueD1jKCJoY2p1biIpLA0KICAgICAgICAgICAgICAgICAgICAgICBieS55PWMoInllYXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCg0KQlJJQy5zdHJhdGVneVsgLCBwZi5sb3dfdm9sIDo9IGlmZWxzZSh2b2xhdGlsaXR5Pmxvd2VyXzIwLCJIaWdoVm9sIiwoaWZlbHNlKHZvbGF0aWxpdHk8PWxvd2VyXzIwLCJMb3dWb2wiLE5BKSkpXQ0KDQp0YWJsZShCUklDLnN0cmF0ZWd5JHBmLmxvd192b2wpDQpkaW0oQlJJQy5zdHJhdGVneSkNCg0KYGBgDQoNCiMjNS4zIEZpbHRlcmluZyBmb3Igc3RyYXRlZ3kgcmVxdWlyZW1lbnRzDQpgYGB7cn0NCiMgZmlsdGVyaW5nIGZvciBncm93dGggc3RvY2tzDQpCUklDLnN0cmF0ZWd5IDwtIHN1YnNldChCUklDLnN0cmF0ZWd5LCBwZi52YWx1ZSA9PSAiR3Jvd3RoIiApDQoNCiMgZmlsdGVyaW5nIGZvciBsb3dWb2wgc3RvY2tzDQpCUklDLnN0cmF0ZWd5IDwtIHN1YnNldChCUklDLnN0cmF0ZWd5LCBwZi5sb3dfdm9sID09ICJMb3dWb2wiICkNCg0KIyBmaWx0ZXJpbmcgZm9yIHdpbm5lciBzdG9ja3MNCkJSSUMuc3RyYXRlZ3kgPC0gc3Vic2V0KEJSSUMuc3RyYXRlZ3ksIHBmLm1vbWVudHVtICA9PSAiV2lubmVyIiApDQoNCmRpbShCUklDLnN0cmF0ZWd5KQ0KDQpzdW1tYXJ5KEJSSUMuc3RyYXRlZ3kpDQpgYGANCg0KIyMgNS40IFN0YXRpc3RpY3Mgb24gU3RyYXRlZ3kgcG9ydGZvbGlvDQpgYGB7cn0NCnN0cmF0LkVxdWFsV2VpZ2h0cyA8LSBhZ2dyZWdhdGUoSWQgfiB5bSwgZGF0YSA9IEJSSUMuc3RyYXRlZ3ksIEZVTj1mdW5jdGlvbih4KSBsZW5ndGgodW5pcXVlKHgpKSkNCmNvbG5hbWVzKHN0cmF0LkVxdWFsV2VpZ2h0cylbMl0gPC0gIk51bWJlck9mU3RvY2tzIg0KIyBhdmVyYWdlIG51bWJlciBvZiBzdG9ja3MNCnN0cmF0ZWd5LmF2Z051bWJlck9mU3RvY2tzIDwtIHN1bShzdHJhdC5FcXVhbFdlaWdodHMkTnVtYmVyT2ZTdG9ja3MpL2xlbmd0aChzdHJhdC5FcXVhbFdlaWdodHMkTnVtYmVyT2ZTdG9ja3MpDQoNCmJlbmNoLkVxdWFsV2VpZ2h0cyA8LSBhZ2dyZWdhdGUoSWQgfiB5bSwgZGF0YSA9IEJSSUMuYmVuY2htYXJrLCBGVU49ZnVuY3Rpb24oeCkgbGVuZ3RoKHVuaXF1ZSh4KSkpDQpjb2xuYW1lcyhiZW5jaC5FcXVhbFdlaWdodHMpWzJdIDwtICJOdW1iZXJPZlN0b2NrcyINCiMgYXZlcmFnZSBudW1iZXIgb2Ygc3RvY2tzDQpiZW5jaG1hcmsuYXZnTnVtYmVyT2ZTdG9ja3MgPC0gc3VtKGJlbmNoLkVxdWFsV2VpZ2h0cyROdW1iZXJPZlN0b2NrcykvbGVuZ3RoKGJlbmNoLkVxdWFsV2VpZ2h0cyROdW1iZXJPZlN0b2NrcykNCmBgYA0KDQojNiBQb3J0Zm9saW8gU3RhdGlzdGljcw0KQWxsIHRlYW1zIHNob3VsZCBwZXJmb3JtIHRoZSBmb2xsb3dpbmcgYW5hbHlzZXM6DQoNCi0gQSBjbGVhciBkZXNjcmlwdGlvbiBvZiB0aGUgc3RyYXRlZ3kgZGVzaWduIChhcHByb2FjaCwgd2VpZ2h0aW5nLCByZWJhbGFuY2luZywuLi4pDQotIFBvcnRmb2xpbyBjaGFyYWN0ZXJpc3RpY3MgKGFubi4gdHVybm92ZXIsIGF2Zy4gbnVtYmVyIG9mIHN0b2NrcywgcG9ydGZvbGlvIGNvbmNlbnRyYXRpb24pDQotIFBlcmZvcm1hbmNlIHN0YXRpc3RpY3MgKHJldHVybiwgdm9sYXRpbGl0eSwgU2hhcnBlIHJhdGlvLCBvdXRwZXJmb3JtYW5jZSwgdHJhY2tpbmcgZXJyb3IsDQppbmZvcm1hdGlvbiByYXRpbywgYWxsIGFubnVhbGl6ZWQpDQotIFZpc3VhbGl6ZSBjdW11bGF0aXZlIHBlcmZvcm1hbmNlIGFuZCBvdXRwZXJmb3JtYW5jZQ0KLSBSZWdyZXNzIHBvcnRmb2xpbyBwZXJmb3JtYW5jZSBvbiBGRjVGTSArIE1vbWVudHVtIGZvciBzdHlsZSBhbmFseXNpcw0KLSBQcm92aWRlIHRoZSB0aW1lLXNlcmllcyBvZiB0aGUgeW91ciBzdHJhdGVneSwgdGhlIGJlbmNobWFyaywgYW5kIEZhbWEtRnJlbmNoIGZhY3RvcnMgYXMNClJEYXRhIGZpbGUNCg0KIyMgNi4xIFdlaWdodCBjb2x1bW4gZm9yIEJSSUMuc3RyYXRlZ3kNCk5PVEUgUlVOIG9ubHkgb25lIG9mIHRoZSA2LjAueCBqdW5rcw0KIyMjIDYuMS4xIEVxdWFsIHdlaWdodHMNCi8vIEV2ZXJ5IHN0b2NrIGhhcyB0aGUgc2FtZSB3ZWlnaHQgd2l0aGluIGEgeW0NCmBgYHtyfQ0KIyBhc3NpZ24gYSBuZXcgd29ya2luZyB2YXJpYWJsZQ0Kc3RyYXRlZ3kgPC0gQlJJQy5zdHJhdGVneQ0KDQpzdHJhdGVneS5FcXVhbFdlaWdodHMgPC0gYWdncmVnYXRlKElkIH4geW0sIGRhdGEgPSBzdHJhdGVneSwgRlVOPWZ1bmN0aW9uKHgpIGxlbmd0aCh1bmlxdWUoeCkpKQ0KY29sbmFtZXMoc3RyYXRlZ3kuRXF1YWxXZWlnaHRzKVsyXSA8LSAiTnVtYmVyT2ZTdG9ja3MiDQoNCiMjIGpvaW4gdmFsdWUgd2VpZ2h0cyB0byBzdG9ja3MNCnN0cmF0ZWd5IDwtIGlubmVyX2pvaW4oeCA9IHN0cmF0ZWd5LCB5ID0gc3RyYXRlZ3kuRXF1YWxXZWlnaHRzLCBieSA9ICJ5bSIpDQoNCiMjIGNhbGN1bGF0ZSB2YWx1ZSB3ZWlnaHQNCnN0cmF0ZWd5JFdlaWdodCA8LSAxL3N0cmF0ZWd5JE51bWJlck9mU3RvY2tzDQoNCiMjIGNhbGN1bGF0ZSB2YWx1ZSB3ZWlnaHQgZXhjZXNzIHJldHVybiAvIHJldHVybg0Kc3RyYXRlZ3kkd1JldCA8LSBzdHJhdGVneSRXZWlnaHQqc3RyYXRlZ3kkUkVULlVTRA0Kc3RyYXRlZ3kkd0V4UmV0IDwtIHN0cmF0ZWd5JFdlaWdodCAqIHN0cmF0ZWd5JFJpUkYNCg0KIyBUT1AgMTAgLS0tLQ0Kc3RyYXRlZ3kuRXF1YWxXZWlnaHRzJHdlaWdodCA8LSAxL3N0cmF0LkVxdWFsV2VpZ2h0cyROdW1iZXJPZlN0b2Nrcw0Kc3RyYXRlZ3kudG9wVGVuQnJpY1QgPC0gbWVhbihzdHJhdGVneS5FcXVhbFdlaWdodHMkd2VpZ2h0KQ0KYGBgDQojIyMgNi4xLjIgVmFsdWUgd2VpZ2h0cw0KLy8gZXZlcnkgc3RvY2sgaGFzIGEgd2VpZ2h0IGFjY29yZGluZyB0byBpdHMgbWFya2V0Y2FwIGluIHRoZSB5bQ0KYGBge3J9DQojIGFzc2lnbiBhIG5ldyB3b3JraW5nIHZhcmlhYmxlDQpzdHJhdGVneSA8LSBCUklDLnN0cmF0ZWd5DQoNCiMgdmFsdWUgd2VpZ2h0IHJldHVybnMNCiMjIGNhbGN1bGF0ZSBtb250aGx5IG1hcmtldCB2YWx1ZSBvdmVyIGFsbCBzdG9ja3MNCnN0cmF0ZWd5LnZhbHVlV2VpZ2h0cyA8LSBhZ2dyZWdhdGUoTE1WLlVTRCB+IHltLCBkYXRhID0gc3RyYXRlZ3ksIEZVTiA9IHN1bSkNCmNvbG5hbWVzKHN0cmF0ZWd5LnZhbHVlV2VpZ2h0cylbMl0gPC0gIlRvdGFsVmFsdWUiDQoNCiMjIGpvaW4gdmFsdWUgd2VpZ2h0cyB0byBzdG9ja3MNCnN0cmF0ZWd5IDwtIGlubmVyX2pvaW4oeCA9IHN0cmF0ZWd5LCB5ID0gc3RyYXRlZ3kudmFsdWVXZWlnaHRzLCBieSA9ICJ5bSIpDQoNCiMjIGNhbGN1bGF0ZSB2YWx1ZSB3ZWlnaHQNCnN0cmF0ZWd5JFdlaWdodCA8LSBzdHJhdGVneSRMTVYuVVNEL3N0cmF0ZWd5JFRvdGFsVmFsdWUNCg0KIyMgY2FsY3VsYXRlIHZhbHVlIHdlaWdodCBleGNlc3MgcmV0dXJuIC8gcmV0dXJuDQpzdHJhdGVneSR3UmV0IDwtIHN0cmF0ZWd5JFdlaWdodCpzdHJhdGVneSRSRVQuVVNEDQpzdHJhdGVneSR3RXhSZXQgPC0gc3RyYXRlZ3kkV2VpZ2h0ICogc3RyYXRlZ3kkUmlSRg0KDQojIFRPUCAxMCAtLS0tDQpzdHJhdGVneV90b3BUZW4gPC0gc3RyYXRlZ3kgJT4lIGFycmFuZ2UoZGVzYyhXZWlnaHQpKSAlPiUgZ3JvdXBfYnkoeW0pICU+JSB0b3Bfbih3dD1XZWlnaHQsMTApDQpzdHJhdGVneS50b3BUZW5CcmljWSA8LSBhZ2dyZWdhdGUoV2VpZ2h0IH4geW0sIGRhdGEgPSBzdHJhdGVneV90b3BUZW4sIEZVTiA9IHN1bSkNCnN0cmF0ZWd5LnRvcFRlbkJyaWNUIDwtIG1lYW4oc3RyYXRlZ3kudG9wVGVuQnJpY1kkV2VpZ2h0KQ0KDQpgYGANCiMjIDYuMiBTdHJhdGVneSBTdGF0aXN0aWNzDQojIyMgNi4yLjEgQlJJQw0KDQpgYGB7cn0NCg0KIyBSRVRVUk5TIC0tLS0NCg0KIyBwZXIgbW9udGgNCnN0cmF0ZWd5LnJldEJyaWNNIDwtIGFnZ3JlZ2F0ZShjYmluZCh3UmV0LHdFeFJldCkgfiB5bSArIGhjanVuLCBkYXRhID0gc3RyYXRlZ3ksRlVOID0gc3VtKQ0KDQojIHBlciB5ZWFyDQpzdHJhdGVneS5yZXRCcmljWSA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gaGNqdW4sIGRhdGEgPSBzdHJhdGVneS5yZXRCcmljTSxGVU4gPSBtZWFuKQ0KIyBhbm51YWxpc2F0aW9uDQpzdHJhdGVneS5yZXRCcmljWSR3UmV0IDwtIHN0cmF0ZWd5LnJldEJyaWNZJHdSZXQgKiAxMg0Kc3RyYXRlZ3kucmV0QnJpY1kkd0V4UmV0IDwtIHN0cmF0ZWd5LnJldEJyaWNZJHdFeFJldCAqIDEyDQojIG1lYW4gcmV0dXJuIG9mIHdob2xlIHBlcmlvZA0Kc3RyYXRlZ3kucmV0QnJpY1QgPC0gbWVhbihzdHJhdGVneS5yZXRCcmljWSR3UmV0KSAjIDE1LjMyOTA5MSAlDQoNCiMgbWVhbiBleGNlc3MgcmV0dXJuIG9mIHdob2xlIHBlcmlvZA0Kc3RyYXRlZ3kucmV0RXhCcmljVCA8LSBtZWFuKHN0cmF0ZWd5LnJldEJyaWNZJHdFeFJldCkgIyAxMy4xMTE1MDkgJQ0KDQojIFNUQU5EQVJEIERFVklBVElPTiAtLS0tDQoNCiMgd2UgY2FsY3VsYXRlIHRoZSBzZCBvdXQgb2YgdGhlIGFubnVhbGlzZWQgcG9ydGZvbGlvIHJldHVybnMNCnN0cmF0ZWd5LnNkQnJpY1QgPC0gc2Qoc3RyYXRlZ3kucmV0QnJpY1kkd1JldCkgIyAzNy4xNTU2ODgNCg0KIyBTSEFSUCBSQVRJTyAtLS0tDQoNCnN0cmF0ZWd5LnNyQnJpY1QgPC0gc3RyYXRlZ3kucmV0RXhCcmljVC9zdHJhdGVneS5zZEJyaWNUICMgMC4zNTI4ODANCg0KIyBNQVggRFJBV0RPV04gLS0tLQ0KDQpkcmF3ZG93biA8LSBmdW5jdGlvbihyZXQpIHsNCiAgIGN1bS5yZXQgIDwtIGMoMCwgY3Vtc3VtKHJldCkpDQogICBkcmF3ZG93biA8LSBjdW0ucmV0IC0gY3VtbWF4KGN1bS5yZXQpDQogICByZXR1cm4odGFpbChkcmF3ZG93biwgLTEpKQ0KfQ0KDQptYXhkcmF3ZG93biA8LSBmdW5jdGlvbihyZXQpbWluKGRyYXdkb3duKHJldCkpDQpyZXQgPC0gc3RyYXRlZ3kucmV0QnJpY1kkd1JldA0Kc3RyYXRlZ3kubWRCcmljVCA8LSBtYXhkcmF3ZG93bihyZXQpICMgLTk5LjE0NjcNCg0KIyBUUkFDS0lORyBFUlJPUiAtLS0tDQoNCiMgbWVyZ2UgcG9ydGZvbGlvIHJldHVybnMgYW5kIGJlbmNobWFyayByZXR1cm5zDQpzdHJhdGVneV9iZW5jaG1hcmsgPC0gaW5uZXJfam9pbih4ID0gc3RyYXRlZ3kucmV0QnJpY1ksIHkgPSBiZW5jaG1hcmsucmV0QnJpY1ksIGJ5ID0gImhjanVuIikNCmNvbG5hbWVzKHN0cmF0ZWd5X2JlbmNobWFyaylbMl0gPC0gIndSZXRfc3RyYXRlZ3kiDQpjb2xuYW1lcyhzdHJhdGVneV9iZW5jaG1hcmspWzNdIDwtICJ3RXhSZXRfc3RyYXRlZ3kiDQpjb2xuYW1lcyhzdHJhdGVneV9iZW5jaG1hcmspWzRdIDwtICJ3UmV0X2JlbmNobWFyayINCmNvbG5hbWVzKHN0cmF0ZWd5X2JlbmNobWFyaylbNV0gPC0gIndFeFJldF9iZW5jaG1hcmsiDQpzdHJhdGVneV9iZW5jaG1hcmskcGZfYWN0aXZlUmV0dXJuIDwtIHN0cmF0ZWd5X2JlbmNobWFyayR3UmV0X3N0cmF0ZWd5IC0gc3RyYXRlZ3lfYmVuY2htYXJrJHdSZXRfYmVuY2htYXJrDQpzdHJhdGVneS50ZUJyaWNUIDwtIHNkKHN0cmF0ZWd5X2JlbmNobWFyayRwZl9hY3RpdmVSZXR1cm4pICMgMjYuODMxNDExICUNCg0KIyBJTkZST01BVElPTiBSQVRJTyAtLS0tDQoNCnN0cmF0ZWd5LmlyQnJpY1QgPC0gbWVhbihzdHJhdGVneV9iZW5jaG1hcmskcGZfYWN0aXZlUmV0dXJuKS9zdHJhdGVneS50ZUJyaWNUICMgMC4yNjc1NA0KYGBgDQoNCiMjIyA2LjIuMiBCeSBjb3VudHJ5DQpJTVBPUlRBTlQgTk9URTogSWYgd2Ugd291bGQgbGlrZSB0byBhcHBseSB0aGUgd2hvbGUgc3RyYXRlZ3kgZm9yIGEgY291bnRyeSBzdGFuZC1hbG9uZSB3ZSB3b3VsZCBoYXZlIHRvIGZpbHRlciBpbiA1LjMgZm9yIGEgY291bnRyeSBhbmQgcnVuIHRoZSAiQlJJQyItY29kZSBpbiBwYXJ0IDYuIEhlcmUgd2UgY2FsY3VsYXRlIHN0YXRpc3RpY3MgZm9yIHNpbmdsZSBjb3VudHJpZXMsIGJ1dCB0aGV5J3JlIGJhc2VkIG9uIGEgcG9ydGZvbGlvIHNlbGVjdGlvbiB3aXRoIHN0b2NrcyBvZiB0aGUgd2hvbGUgQlJJQyByZWdpb24uIC0tPiBzdHJvbmcgQklBUw0KDQpgYGB7cn0NCg0KIyBSRVRVUk5TDQoNCiMgcGVyIG1vbnRoDQpzdHJhdGVneS5yZXRDb3VudHJ5TSA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gY291bnRyeS54ICsgeW0gKyBoY2p1biwgZGF0YSA9IHN0cmF0ZWd5LEZVTiA9IHN1bSkNCiMgcGVyIHllYXINCnN0cmF0ZWd5LnJldENvdW50cnlZIDwtIGFnZ3JlZ2F0ZShjYmluZCh3UmV0LHdFeFJldCkgfiBjb3VudHJ5LnggKyBoY2p1biwgZGF0YSA9IHN0cmF0ZWd5LnJldENvdW50cnlNLEZVTiA9IG1lYW4pDQojIGFubnVhbGlzYXRpb24NCnN0cmF0ZWd5LnJldENvdW50cnlZJHdSZXQgPC0gc3RyYXRlZ3kucmV0Q291bnRyeVkkd1JldCAqIDEyDQpzdHJhdGVneS5yZXRDb3VudHJ5WSR3RXhSZXQgPC0gc3RyYXRlZ3kucmV0Q291bnRyeVkkd0V4UmV0ICogMTINCiMgbWVhbiBleGNlc3MgcmV0dXJuIGFuZCByZXR1cm4gb2Ygd2hvbGUgcGVyaW9kDQpzdHJhdGVneS5yZXRDb3VudHJ5VCA8LSBhZ2dyZWdhdGUoY2JpbmQod1JldCx3RXhSZXQpIH4gY291bnRyeS54LCBkYXRhID0gc3RyYXRlZ3kucmV0Q291bnRyeVksRlVOID0gbWVhbikNCg0KIyBTVEFOREFSRCBERVZJQVRJT04NCnN0cmF0ZWd5LnNkQ291bnRyeVQgPC0gYWdncmVnYXRlKHdSZXQgfiBjb3VudHJ5LngsIGRhdGEgPSBzdHJhdGVneS5yZXRDb3VudHJ5WSwgRlVOID0gc2QpDQpjb2xuYW1lcyhzdHJhdGVneS5zZENvdW50cnlUKVsyXSA8LSAiU0R3aG9sZXBlcmlvZCINCg0KIyBTSEFSUCBSQVRJTw0KDQpzdHJhdGVneS5zckNvdW50cnlUID0gaW5uZXJfam9pbih4ID0gc3RyYXRlZ3kucmV0Q291bnRyeVQsIHkgPSBzdHJhdGVneS5zZENvdW50cnlULCBieSA9ICJjb3VudHJ5LngiICkNCnN0cmF0ZWd5LnNyQ291bnRyeVQkU1IgPC0gc3RyYXRlZ3kuc3JDb3VudHJ5VCR3RXhSZXQvc3RyYXRlZ3kuc3JDb3VudHJ5VCRTRHdob2xlcGVyaW9kDQoNCiMgTUFYIERSQVdET1dODQojIHRkDQoNCg0KIyBUUkFDS0lORyBFUlJPUg0KDQojIG1lcmdlIHBvcnRmb2xpbyByZXR1cm5zIGFuZCBiZW5jaG1hcmsgcmV0dXJucw0Kc3RyYXRlZ3lfYmVuY2htYXJrX2MgPC0gaW5uZXJfam9pbih4ID0gc3RyYXRlZ3kucmV0Q291bnRyeVksIHkgPSBiZW5jaG1hcmsucmV0Q291bnRyeVksIGJ5ID0gYygiaGNqdW4iLCJjb3VudHJ5LngiKSkNCmNvbG5hbWVzKHN0cmF0ZWd5X2JlbmNobWFya19jKVszXSA8LSAid1JldF9wb3J0Zm9saW8iDQpjb2xuYW1lcyhzdHJhdGVneV9iZW5jaG1hcmtfYylbNF0gPC0gIndFeFJldF9wb3J0Zm9saW8iDQpjb2xuYW1lcyhzdHJhdGVneV9iZW5jaG1hcmtfYylbNV0gPC0gIndSZXRfYmVuY2htYXJrIg0KY29sbmFtZXMoc3RyYXRlZ3lfYmVuY2htYXJrX2MpWzZdIDwtICJ3RXhSZXRfYmVuY2htYXJrIg0Kc3RyYXRlZ3lfYmVuY2htYXJrX2MkcGZfYWN0aXZlUmV0dXJuIDwtIHN0cmF0ZWd5X2JlbmNobWFya19jJHdSZXRfcG9ydGZvbGlvIC0gc3RyYXRlZ3lfYmVuY2htYXJrX2Mkd1JldF9iZW5jaG1hcmsNCg0Kc3RyYXRlZ3kudGVDb3VudHJ5VCA8LSBhZ2dyZWdhdGUocGZfYWN0aXZlUmV0dXJuIH4gY291bnRyeS54LCBkYXRhID0gc3RyYXRlZ3lfYmVuY2htYXJrX2MsIEZVTiA9IHNkKQ0KY29sbmFtZXMoc3RyYXRlZ3kudGVDb3VudHJ5VClbMl0gPC0gIlRyYWNraW5nRXJyb3IiDQoNCiMgSU5GUk9NQVRJT04gUkFUSU8NCnN0cmF0ZWd5LmlyQ291bnRyeVRfaW50ZXJtZWRpYXRlIDwtIGFnZ3JlZ2F0ZShwZl9hY3RpdmVSZXR1cm4gfiBjb3VudHJ5LngsIGRhdGEgPSBzdHJhdGVneV9iZW5jaG1hcmtfYywgRlVOID0gbWVhbikNCmNvbG5hbWVzKHN0cmF0ZWd5LmlyQ291bnRyeVRfaW50ZXJtZWRpYXRlKVsyXSA8LSAibWVhbkFjdGl2ZVJldCINCg0Kc3RyYXRlZ3kuaXJDb3VudHJ5VCA8LSBpbm5lcl9qb2luKHggPSBzdHJhdGVneS50ZUNvdW50cnlULCB5ID0gc3RyYXRlZ3kuaXJDb3VudHJ5VF9pbnRlcm1lZGlhdGUsIGJ5ID0gImNvdW50cnkueCIpDQpzdHJhdGVneS5pckNvdW50cnlUJEluZm9ybWF0aW9uUmF0aW8gPC0gc3RyYXRlZ3kuaXJDb3VudHJ5VCRtZWFuQWN0aXZlUmV0IC8gc3RyYXRlZ3kuaXJDb3VudHJ5VCRUcmFja2luZ0Vycm9yDQoNCmBgYA0KIyMgNi4zIEJlbmNobWFyayBTdGF0aXN0aWNzDQoNCmBgYHtyfQ0KIyBtZWFuIHJldHVybiBvZiB3aG9sZSBwZXJpb2QNCmJlbmNobWFyay5yZXRCcmljVCA8LSBtZWFuKGJlbmNobWFyay5yZXRCcmljWSR3UmV0KSANCg0KIyBtZWFuIGV4Y2VzcyByZXR1cm4gb2Ygd2hvbGUgcGVyaW9kDQpiZW5jaG1hcmsucmV0RXhCcmljVCA8LSBtZWFuKGJlbmNobWFyay5yZXRCcmljWSR3RXhSZXQpDQoNCiMgU1RBTkRBUkQgREVWSUFUSU9ODQoNCiMgd2UgY2FsY3VsYXRlIHRoZSBzZCBvdXQgb2YgdGhlIGFubnVhbGlzZWQgcG9ydGZvbGlvIHJldHVybnMNCmJlbmNobWFyay5zZEJyaWNUIDwtIHNkKGJlbmNobWFyay5yZXRCcmljWSR3UmV0KSANCg0KIyBTSEFSUCBSQVRJTw0KDQpiZW5jaG1hcmsuc3JCcmljVCA8LSBiZW5jaG1hcmsucmV0RXhCcmljVC9iZW5jaG1hcmsuc2RCcmljVCANCg0KIyBNQVggRFJBV0RPV04NCg0KZHJhd2Rvd24gPC0gZnVuY3Rpb24ocmV0KSB7DQogICBjdW0ucmV0ICA8LSBjKDAsIGN1bXN1bShyZXQpKQ0KICAgZHJhd2Rvd24gPC0gY3VtLnJldCAtIGN1bW1heChjdW0ucmV0KQ0KICAgcmV0dXJuKHRhaWwoZHJhd2Rvd24sIC0xKSkNCn0NCg0KbWF4ZHJhd2Rvd24gPC0gZnVuY3Rpb24ocmV0KW1pbihkcmF3ZG93bihyZXQpKQ0KcmV0IDwtIGJlbmNobWFyay5yZXRCcmljWSR3UmV0DQpiZW5jaG1hcmsubWRCcmljVCA8LSBtYXhkcmF3ZG93bihyZXQpIA0KDQojIFRSQUNLSU5HIEVSUk9SDQoNCiMgbWVyZ2UgcG9ydGZvbGlvIHJldHVybnMgYW5kIGJlbmNobWFyayByZXR1cm5zDQpiZW5jaG1hcmtfYmVuY2htYXJrIDwtIGlubmVyX2pvaW4oeCA9IGJlbmNobWFyay5yZXRCcmljWSwgeSA9IGJlbmNobWFyay5yZXRCcmljWSwgYnkgPSAiaGNqdW4iKQ0KY29sbmFtZXMoYmVuY2htYXJrX2JlbmNobWFyaylbMl0gPC0gIndSZXRfYmVuY2htYXJrIg0KY29sbmFtZXMoYmVuY2htYXJrX2JlbmNobWFyaylbM10gPC0gIndFeFJldF9iZW5jaG1hcmsiDQpjb2xuYW1lcyhiZW5jaG1hcmtfYmVuY2htYXJrKVs0XSA8LSAid1JldF9iZW5jaG1hcmsiDQpjb2xuYW1lcyhiZW5jaG1hcmtfYmVuY2htYXJrKVs1XSA8LSAid0V4UmV0X2JlbmNobWFyayINCmJlbmNobWFya19iZW5jaG1hcmskcGZfYWN0aXZlUmV0dXJuIDwtIGJlbmNobWFya19iZW5jaG1hcmskd1JldF9iZW5jaG1hcmsgLSBiZW5jaG1hcmtfYmVuY2htYXJrJHdSZXRfYmVuY2htYXJrDQpiZW5jaG1hcmsudGVCcmljVCA8LSBzZChiZW5jaG1hcmtfYmVuY2htYXJrJHBmX2FjdGl2ZVJldHVybikNCg0KIyBJTkZST01BVElPTiBSQVRJTw0KDQpiZW5jaG1hcmsuaXJCcmljVCA8LSBtZWFuKGJlbmNobWFya19iZW5jaG1hcmskcGZfYWN0aXZlUmV0dXJuKS9iZW5jaG1hcmsudGVCcmljVA0KDQojIFRPUCAxMCAtLS0tDQpiZW5jaG1hcmtfdG9wVGVuIDwtIEJSSUMuYmVuY2htYXJrICU+JSBhcnJhbmdlKGRlc2MoVmFsdWVXZWlnaHQpKSAlPiUgZ3JvdXBfYnkoeW0pICU+JSB0b3Bfbih3dD1WYWx1ZVdlaWdodCwxMCkNCmJlbmNobWFyay50b3BUZW5CcmljWSA8LSBhZ2dyZWdhdGUoVmFsdWVXZWlnaHQgfiB5bSwgZGF0YSA9IGJlbmNobWFya190b3BUZW4sIEZVTiA9IHN1bSkNCmJlbmNobWFyay50b3BUZW5CcmljVCA8LSBtZWFuKGJlbmNobWFyay50b3BUZW5CcmljWSRWYWx1ZVdlaWdodCkNCg0KYGBgDQoNCiMjIDYuNCBUdXJub3Zlcg0KYGBge3J9DQpsaWJyYXJ5KHJlc2hhcGUpDQpsaWJyYXJ5KHh0cykNCg0KIyBzdHJhdGVneSB0dXJub3ZlciAtLS0tDQojIGdldCBpbnRlcm1lZGlhdGUgZGF0YSBmcmFtZQ0KdHVybm92ZXJfY2FsYyA8LSBzdHJhdGVneQ0KDQpzX3dlaWdodHMgPC0gc3Vic2V0KHR1cm5vdmVyX2NhbGMsc2VsZWN0PSBjKCJ5bSIsIldlaWdodCIsIklkIikpDQpzX3dlaWdodHMgPC1yZXNoYXBlKHNfd2VpZ2h0cywgaWR2YXIgPSAieW0iLCB0aW1ldmFyID0gIklkIiwgZGlyZWN0aW9uID0gIndpZGUiKQ0Kc193ZWlnaHRzIDwtYXMueHRzKHNfd2VpZ2h0cykNCnNfd2VpZ2h0c1tpcy5uYShzX3dlaWdodHMpXT0wDQoNCnNfbGVhZF93ZWlnaHRzIDwtIGFzLmRhdGEuZnJhbWUoc193ZWlnaHRzKQ0Kc19sZWFkX3dlaWdodHMgPC1zX2xlYWRfd2VpZ2h0cyAlPiUgbXV0YXRlX2FsbChsZWFkKQ0KYXMuZGF0YS5mcmFtZShzX2xlYWRfd2VpZ2h0cykNCg0Kc19sZWFkX3dlaWdodHM8LWFzLmRhdGEuZnJhbWUoc19sZWFkX3dlaWdodHMpDQpzX3dlaWdodHM8LWFzLmRhdGEuZnJhbWUoc193ZWlnaHRzKQ0KDQpzX3R1cm5vdmVyX3dlaWdodHM8LWFzLmRhdGEuZnJhbWUodHhucyA8LSBzX2xlYWRfd2VpZ2h0cyAtIHNfd2VpZ2h0cykgI3NfdHVub3Zlcl93ZWlnaHRzIC0gc3R1ZmYgaW5zaWRlIHRoZSBicmFja2VyIGluIHRoZSBmcm9tdWxhDQpzX3R1cm5vdmVyX3dlaWdodHNbaXMubmEoc190dXJub3Zlcl93ZWlnaHRzKV09MA0Kc190dXJub3Zlcl9wYXR0ZXJuIDwtIGFzLmRhdGEuZnJhbWUocm93U3VtcyhhYnMoc190dXJub3Zlcl93ZWlnaHRzWywxOmxlbmd0aChzX3R1cm5vdmVyX3dlaWdodHMpXSkpLG9yZGVyLmJ5PWluZGV4KHNfdHVybm92ZXJfd2VpZ2h0cykpDQpjb2xuYW1lcyhzX3R1cm5vdmVyX3BhdHRlcm4pWzFdIDwtICJvbmUiDQoNCnNfdHVybm92ZXJfcGF0dGVybjwtYXMuZGF0YS5mcmFtZShzX3R1cm5vdmVyX3BhdHRlcm4pDQpzdHJhdGVneS50dXJub3ZlciA8LSAoc3VtKHNfdHVybm92ZXJfcGF0dGVybiRvbmUpIC8gKDIqbnJvdyhzX3R1cm5vdmVyX3BhdHRlcm4pKSkNCg0KIyBiZW5jaG1hcmsgdHVybm92ZXIgLS0tLQ0KIyBnZXQgaW50ZXJtZWRpYXRlIGRhdGEgZnJhbWUNCnR1cm5vdmVyX2NhbGMgPC0gQlJJQy5iZW5jaG1hcmsNCg0Kc193ZWlnaHRzIDwtIHN1YnNldCh0dXJub3Zlcl9jYWxjLHNlbGVjdD0gYygieW0iLCJWYWx1ZVdlaWdodCIsIklkIikpDQpzX3dlaWdodHMgPC1yZXNoYXBlKHNfd2VpZ2h0cywgaWR2YXIgPSAieW0iLCB0aW1ldmFyID0gIklkIiwgZGlyZWN0aW9uID0gIndpZGUiKQ0Kc193ZWlnaHRzIDwtYXMueHRzKHNfd2VpZ2h0cykNCnNfd2VpZ2h0c1tpcy5uYShzX3dlaWdodHMpXT0wDQoNCnNfbGVhZF93ZWlnaHRzIDwtIGFzLmRhdGEuZnJhbWUoc193ZWlnaHRzKQ0Kc19sZWFkX3dlaWdodHMgPC1zX2xlYWRfd2VpZ2h0cyAlPiUgbXV0YXRlX2FsbChsZWFkKQ0KYXMuZGF0YS5mcmFtZShzX2xlYWRfd2VpZ2h0cykNCg0Kc19sZWFkX3dlaWdodHM8LWFzLmRhdGEuZnJhbWUoc19sZWFkX3dlaWdodHMpDQpzX3dlaWdodHM8LWFzLmRhdGEuZnJhbWUoc193ZWlnaHRzKQ0KDQpzX3R1cm5vdmVyX3dlaWdodHM8LWFzLmRhdGEuZnJhbWUodHhucyA8LSBzX2xlYWRfd2VpZ2h0cyAtIHNfd2VpZ2h0cykgI3NfdHVub3Zlcl93ZWlnaHRzIC0gc3R1ZmYgaW5zaWRlIHRoZSBicmFja2VyIGluIHRoZSBmcm9tdWxhDQpzX3R1cm5vdmVyX3dlaWdodHNbaXMubmEoc190dXJub3Zlcl93ZWlnaHRzKV09MA0Kc190dXJub3Zlcl9wYXR0ZXJuIDwtIGFzLmRhdGEuZnJhbWUocm93U3VtcyhhYnMoc190dXJub3Zlcl93ZWlnaHRzWywxOmxlbmd0aChzX3R1cm5vdmVyX3dlaWdodHMpXSkpLG9yZGVyLmJ5PWluZGV4KHNfdHVybm92ZXJfd2VpZ2h0cykpDQpjb2xuYW1lcyhzX3R1cm5vdmVyX3BhdHRlcm4pWzFdIDwtICJvbmUiDQoNCnNfdHVybm92ZXJfcGF0dGVybjwtYXMuZGF0YS5mcmFtZShzX3R1cm5vdmVyX3BhdHRlcm4pDQpiZW5jaG1hcmsudHVybm92ZXIgPC0gKHN1bShzX3R1cm5vdmVyX3BhdHRlcm4kb25lKSAvICgyKm5yb3coc190dXJub3Zlcl9wYXR0ZXJuKSkpDQpgYGANCg0KDQojIyA2LjUgU2F2aW5nIFN0YXRpc3RpY3MgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lDQpgYGB7cn0NCmZ1bGxfQlJJQ19WYWx1ZVdlaWdodCA8LSBjKHN0cmF0ZWd5LnJldEJyaWNULHN0cmF0ZWd5LnJldEV4QnJpY1Qsc3RyYXRlZ3kuc2RCcmljVCxzdHJhdGVneS5zckJyaWNULHN0cmF0ZWd5Lm1kQnJpY1Qsc3RyYXRlZ3kudGVCcmljVCxzdHJhdGVneS5pckJyaWNULCBzdHJhdGVneS5hdmdOdW1iZXJPZlN0b2Nrcywgc3RyYXRlZ3kudG9wVGVuQnJpY1QsIHN0cmF0ZWd5LnR1cm5vdmVyKQ0KDQpmdWxsX0JSSUNfQmVuY2htYXJrIDwtIGMoYmVuY2htYXJrLnJldEJyaWNULGJlbmNobWFyay5yZXRFeEJyaWNULGJlbmNobWFyay5zZEJyaWNULGJlbmNobWFyay5zckJyaWNULGJlbmNobWFyay5tZEJyaWNULGJlbmNobWFyay50ZUJyaWNULGJlbmNobWFyay5pckJyaWNULCBiZW5jaG1hcmsuYXZnTnVtYmVyT2ZTdG9ja3MsIGJlbmNobWFyay50b3BUZW5CcmljVCwgYmVuY2htYXJrLnR1cm5vdmVyKQ0KDQpmdWxsX0JSSUNfVmFsdWVXZWlnaHQNCmBgYA0KDQoNCiMgNyBTcGFubmluZyB0ZXN0cyAoZmFjdG9yIGV4cG9zdXJlKQ0KDQpgYGB7cn0NCiMgam9pbiBmYWN0b3JzLCBzdHJhdGVneSBhbmQgYmVuY2htYXJrIC0tLS0NCnNwYW5uaW5nXzEgPC0gbGVmdF9qb2luKHggPSBmYWN0b3JzLCB5ID0gc3RyYXRlZ3kucmV0QnJpY00sIGJ5ID0gInltIikNCnNwYW5uaW5nIDwtIGxlZnRfam9pbih4ID0gc3Bhbm5pbmdfMSwgeSA9IG1hcmtldC5yZXRCcmljTSwgYnkgPSAieW0iKQ0KY29sbmFtZXMoc3Bhbm5pbmcpWzhdIDwtICJTdHJhdGVneV9SRVQiDQpjb2xuYW1lcyhzcGFubmluZylbOV0gPC0gIlN0cmF0ZWd5X1JpUkYiDQpjb2xuYW1lcyhzcGFubmluZylbMTFdIDwtICJNYXJrZXRfUkVUIg0KY29sbmFtZXMoc3Bhbm5pbmcpWzEyXSA8LSAiTWFya2V0X1JpUkYiDQoNCiMgY29ycmVsYXRpb24gbWF0cml4IGJldHdlZW4gZmFjdG9ycw0KDQpoZWFkKHNwYW5uaW5nKQ0KDQpkaW0oc3Bhbm5pbmcpICMgMjgwICgyNCB5ZWFycyAqIDEyIG1vbnRocykgeCA1DQoNCiMjIGNvcihzcGFubmluZ1ssLSJ5bSJdKSAjIGNvcnJlbGF0aW9uIG1hdHJpeCBiZXR3ZWVuIGZhY3RvcnMgZm9yIHRoZSBCUklDIHJlZ2lvbg0KDQpzdW1tYXJ5KHNwYW5uaW5nKSAjIHRvIHVzZSBmb3IgYSB0YWJsZQ0KDQojIFNwYW5uaW5nIFRlc3RzIC0tLS0NCiMjIEZGM0ZNDQpzdW1tYXJ5KGxtKGRhdGE9c3Bhbm5pbmcsIGZvcm11bGEgPSBTdHJhdGVneV9SaVJGIH4gTWFya2V0X1JpUkYgKyBTTUIgKyBITUwpKQ0KDQojIyBGRjVGTQ0Kc3VtbWFyeShsbShkYXRhPXNwYW5uaW5nLCBmb3JtdWxhID0gU3RyYXRlZ3lfUmlSRiB+IE1hcmtldF9SaVJGICsgU01CICsgSE1MICsgQ01BICsgUk1XKSkNCg0KIyMgRkYzRk0gKyBNT00NCnN1bW1hcnkobG0oZGF0YT1zcGFubmluZywgZm9ybXVsYSA9IFN0cmF0ZWd5X1JpUkYgfiBNYXJrZXRfUmlSRiArIFNNQiArIEhNTCArIE1PTSkpDQoNCiMjIEZGNUZNICsgTU9NDQpzdW1tYXJ5KGxtKGRhdGE9c3Bhbm5pbmcsIGZvcm11bGEgPSBTdHJhdGVneV9SaVJGIH4gTWFya2V0X1JpUkYgKyBTTUIgKyBITUwgKyBDTUEgKyBSTVcgKyBNT00pKQ0KDQoNCmBgYA0KIyA4IFBsb3RzIGFuZCBWaXN1YWxpc2F0aW9uDQpMaXN0IG9mIHBsb3RzOg0KMSkgQ3VtbXVsYXRpdmUgcGVyZm9ybWFuY2UgQmVuY2htYXJrIHZzIFN0cmF0ZWd5IEJSSUMgLy8gVklOSVQvTUFOVSByZXZpc2l0DQoyKSBTaW5nbGUgZmFjdG9ycyB2cyBtdWx0aWZhY3RvciBwb3J0Zm9saW8gaW4gcmlzay1yZXR1cm4gc3BhY2UgLy8gTUFOVSByZXZpc2l0DQozKSBFdm9sdXRpb24gb2YgTWFya2V0Q2FwIHdlaWdodHMgcGVyIGNvdW50cnkgLS0+IHJlZ2lvbmFsIHdlaWdodGluZyAoaW1wbGljaXQpIC8vID8/IC8vIHVzZSBHRFAgcGxvdCBjb2RlIGFuZCB1cGRhdGUgaXQgDQoNCkxpc3Qgb2YgdGFibGVzOg0KMSkgUGVyZm9ybWFuY2UgYW5kIHJpc2sgLy8gTUFOVSByZXZpc2l0IC0tPiBKT0hBTk5FUyBnaXZlcyB0aGUgZGF0YQ0KMikgSW52ZXN0YWJpbGl0eSAvLyBNQU5VIHJldmlzaXQNCjMpIFNwYW5uaW5nIHRlc3RzX1N0eWxlIGV4cG9zdXJlIC8vDQoNClRhYmxlL1Bsb3Q6DQoxKSBTdHJhdGVneSBCUklDIHZzIENvdW50cmllcyBzdGFuZCBhbG9uZSAvLyBKT0hBTk5FUyAjIyBUYWJsZXMgZG9uZQ0KMikgU3RyYXRlZ3kgcGFydHMgc3RhbmQgYWxvbmUgYW5kL29yIDIgY29tYmluZWQgdnMgM3BsZSBzb3J0IC8vIEpvaGFubmVzICMjIFRhYmxlcyBkb25lDQoNCmBgYHtyfQ0KIyBsb2FkIHN0YXRzIGRhdGEgLS0tLQ0KbG9hZCgic3RhdGlzdGljcy9kaWZmZXJlbnRTdHJhdGVnaWVzX2FsbC5SRGF0YSIpDQpsb2FkKCJzdGF0aXN0aWNzL2RpZmZlcmVudFN0cmF0ZWdpZXNfQlJJQy5SRGF0YSIpDQpsb2FkKCJzdGF0aXN0aWNzL2RpZmZlcmVudFN0cmF0ZWdpZXNfQ0hOLlJEYXRhIikNCmxvYWQoInN0YXRpc3RpY3MvZGlmZmVyZW50U3RyYXRlZ2llc19SVVMuUkRhdGEiKQ0KbG9hZCgic3RhdGlzdGljcy9kaWZmZXJlbnRTdHJhdGVnaWVzX0lORC5SRGF0YSIpDQpsb2FkKCJzdGF0aXN0aWNzL2RpZmZlcmVudFN0cmF0ZWdpZXNfQlJBLlJEYXRhIikNCmxvYWQoInN0YXRpc3RpY3MvZmFjdG9yc19CUklDLlJEYXRhIikNCmxvYWQoInN0YXRpc3RpY3MvZmFjdG9yc19DSE4uUkRhdGEiKQ0KbG9hZCgic3RhdGlzdGljcy9mYWN0b3JzX1JVUy5SRGF0YSIpDQpsb2FkKCJzdGF0aXN0aWNzL2ZhY3RvcnNfSU5ELlJEYXRhIikNCmxvYWQoInN0YXRpc3RpY3MvZmFjdG9yc19CUkEuUkRhdGEiKQ0KYGBgDQoNCiMjIDguMSBCZW5jaG1hcmsgdnMgU3RyYXRlZ3kNCmBgYHtyfQ0KIyBTdHJhdGVneSB2cyBiZW5jaG1hcmsgcGxvdHMNCmRpbShiZW5jaG1hcmsucmV0QnJpY00pDQpkaW0oc3RyYXRlZ3kucmV0QnJpY00pDQoNCiMgaW5uZXIgam9pbiANCmJtX3Bsb3RfZGYgPC0gaW5uZXJfam9pbih4PWJlbmNobWFyay5yZXRCcmljTSwgeT1zdHJhdGVneS5yZXRCcmljTSwgYnk9InltIikNCg0KYm1fcGxvdF9kZg0KDQojIHpvbyBvYmplY3RzIGZvciBjdW1tdWxhdGl2ZSBwZXJmb3JtYW5jZSANCmJlbmNobWFyay56b28gPC0gem9vKGJtX3Bsb3RfZGYkd1JldC54KSAjIHpvbyBvYmplY3QNCg0KIyBjdW1tdWxhdGl2ZSBwZXJmb3JtYW5jZSBvZiAxIEVVUg0KYm1fcGxvdF9kZiRibS5jdW1fcmV0IDwtIGN1bXN1bShsb2coMStiZW5jaG1hcmsuem9vLzEwMCkpICMgY3VtIGxvZyByZXR1cm5zDQoNCnN0cmF0ZWd5LnpvbyA8LSB6b28oYm1fcGxvdF9kZiR3UmV0LnkpDQoNCmJtX3Bsb3RfZGYkc3RyYXQuY3VtX3JldCA9IGN1bXN1bShsb2coMStzdHJhdGVneS56b28vMTAwKSkNCg0KDQoNCiMgY3JlYXRpbmcgYSBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nIHRoZSBjdW1tdWxhdGl2ZSByZXR1cm5zDQpkZl9uZXcgPC0gZGF0YS5mcmFtZShibS5jcmV0ID0gYXMudmVjdG9yKGJtX3Bsb3RfZGYkYm0uY3VtX3JldCksDQogICAgICAgICAgICAgICAgICAgICBzdHJhdC5jcmV0ID0gYXMudmVjdG9yKGJtX3Bsb3RfZGYkc3RyYXQuY3VtX3JldCksDQogICAgICAgICAgICAgICAgICAgICB0aW1lID0gYm1fcGxvdF9kZiR5bSkNCg0KIyBzYXZpbmcgdGhlIHBsb3QgYXMgYSBqcGVnIGZpbGUNCmpwZWcoInN0cmF0ZWd5X3ZzX2JtX3Bsb3QuanBlZyIsIHdpZHRoID0gNDgwLCBoZWlnaHQgPSA0ODApICMgaGVpZ2h0IGFuZCB3aWR0aCBjYW4gYmUgY2hvc2VuIGFzIHlvdXIgd2lzaCANCg0KIyBzdHJhdGVneSByZXR1cm5zIHZzIGJpZyBzdG9ja3MgYmVuY2htYXJrIA0Kc3RyYXRlZ3lfdnNfYm1fcmV0dXJucyA8LSBnZ3Bsb3QoZGF0YSA9IGJtX3Bsb3RfZGYsIGFlcyh4ID0geW0pKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBibS5jdW1fcmV0LCBjb2xvdXI9ImJtLmN1bV9yZXQiKSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gc3RyYXQuY3VtX3JldCwgY29sb3VyPSJzdHJhdC5jdW1fcmV0IikpICsgDQogIGxhYnMoeT0gIkN1bS4gTG9nIFJldHVybnMiLCB4ID0gIlllYXIiLCB0aXRsZSA9Ik1vbnRobHkgQ3VtLiBMb2cgUmV0dXJuczogM0ZTdHJhdGVneSB2cyBCZW5jaG1hcmsiKSArICMgeCBhbmQgeSBheGlzIGxhYmxlcyBhbmQgcGxvdCB0aXRsZQ0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iUG9ydGZvbGlvIiwgDQogICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygiYm0uY3VtX3JldCIsICJzdHJhdC5jdW1fcmV0IiksDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPSBjKCJCZW5jaG1hcmsiLCIzRlN0cmF0ZWd5IiksICMgbGVnZW5kIGxhYmVsIG5hbWVzDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmVkIiwgImdyZWVuIikpDQogIA0Kc3RyYXRlZ3lfdnNfYm1fcmV0dXJucw0KDQojIHNlY29uZCBwYXJ0IG9mIHRoZSBjb2RlIHRoYXQgY3JlYXRlcyB0aGUganBlZyBmaWxlIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkNCmBgYA0KDQojIyA4LjIgRmFjdG9yIFJldHVybnMNCmBgYHtyfQ0KIyBmYWN0b3IgcmV0dXJuIHBsb3RzDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmNtYS56b28gPC0gem9vKGZhY3RvcnMkQ01BKSAjIHpvbyBvYmplY3QNCg0KZmFjdG9ycyRjbWEuY3VtX3JldCA9IGN1bXN1bShsb2coMStjbWEuem9vLzEwMCkpICMgY3VtIGxvZyByZXR1cm5zDQoNCmhtbC56b28gPC0gem9vKGZhY3RvcnMkSE1MKQ0KDQpmYWN0b3JzJGhtbC5jdW1fcmV0ID0gY3Vtc3VtKGxvZygxK2htbC56b28vMTAwKSkNCg0Kcm13LnpvbyA8LSB6b28oZmFjdG9ycyRSTVcpDQoNCmZhY3RvcnMkcm13LmN1bV9yZXQgPSBjdW1zdW0obG9nKDErcm13Lnpvby8xMDApKQ0KDQpzbWIuem9vIDwtIHpvbyhmYWN0b3JzJFNNQikNCg0KZmFjdG9ycyRzbWIuY3VtX3JldCA9IGN1bXN1bShsb2coMStzbWIuem9vLzEwMCkpDQoNCg0KDQojIGNyZWF0aW5nIGEgZGF0YWZyYW1lIGZvciBwbG90dGluZyB0aGUgY3VtbXVsYXRpdmUgcmV0dXJucw0KZGZfbmV3IDwtIGRhdGEuZnJhbWUoY21hLmNyZXQgPSBhcy52ZWN0b3IoZmFjdG9ycyRjbWEuY3VtX3JldCksDQogICAgICAgICAgICAgICAgICAgICBzbWIuY3JldCA9IGFzLnZlY3RvcihmYWN0b3JzJHNtYi5jdW1fcmV0KSwNCiAgICAgICAgICAgICAgICAgICAgIGhtbC5jcmV0ID0gYXMudmVjdG9yKGZhY3RvcnMkaG1sLmN1bV9yZXQpLA0KICAgICAgICAgICAgICAgICAgICAgcm13LmNyZXQgPSBhcy52ZWN0b3IoZmFjdG9ycyRybXcuY3VtX3JldCksDQogICAgICAgICAgICAgICAgICAgICB0aW1lID0gYXMuRGF0ZShmYWN0b3JzJHltKSkNCg0KIyBwbG90IG9mIHRoZSBmYWN0b3IgcmV0dXJucyAobG9nIHNjYWxlKQ0KY3VtX3JldHMgPC0gZ2dwbG90KGRhdGEgPSBkZl9uZXcsIGFlcyh4ID0gdGltZSkpICAgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBzbWIuY3JldCwgY29sb3VyPSJzbWIuY3JldCIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBobWwuY3JldCwgY29sb3VyPSJobWwuY3JldCIpKSArDQogIGdlb21fbGluZShhZXMoeSA9IHJtdy5jcmV0LCBjb2xvdXI9InJtdy5jcmV0IikpICsgDQogIGdlb21fbGluZShhZXMoeSA9IGNtYS5jcmV0LCBjb2xvdXI9ImNtYS5jcmV0IikpICsgDQogIGxhYnMoeT0gImN1bS4gbG9nIHJldHVybiIsIHggPSAiWWVhciIsIHRpdGxlID0iTW9udGhseSBjdW0uIGZhY3RvciBsb2cgcmV0dXJucyIpICsgIyB4IGFuZCB5IGF4aXMgbGFibGVzIGFuZCBwbG90IHRpdGxlDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbChuYW1lPSJGYWN0b3IiLCANCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJzbWIuY3JldCIsICJobWwuY3JldCIsICJybXcuY3JldCIsICJjbWEuY3JldCIpLA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJlZCIsICJncmVlbiIsICJibHVlIiwib3JhbmdlIikpDQogIA0KY3VtX3JldHMNCiANCg0KIyBmYWN0b3IgcmV0dXJucyAocmVndWxhciBzY2FsZSkNCmZhY3Rvcl9yZXR1cm5zIDwtIGdncGxvdChkYXRhID0gZmFjdG9ycywgYWVzKHggPSB5bSkpICsgDQogIGdlb21fbGluZShhZXMoeSA9IFNNQiwgY29sb3VyPSJTTUIiKSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gSE1MLCBjb2xvdXI9IkhNTCIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBSTVcsIGNvbG91cj0iUk1XIikpICsgDQogIGdlb21fbGluZShhZXMoeSA9IENNQSwgY29sb3VyPSJDTUEiKSkgKyANCiAgbGFicyh5PSAiY291bnRyeSB3ZWlnaHQiLCB4ID0gIlllYXIiLCB0aXRsZSA9Ik1vbnRobHkgZmFjdG9yIHJldHVybnMiKSArICMgeCBhbmQgeSBheGlzIGxhYmxlcyBhbmQgcGxvdCB0aXRsZQ0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iQ291bnRyeSB3ZWlnaHQiLCANCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJTTUIiLCAiSE1MIiwgIlJNVyIsICJDTUEiKSwNCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQiLCAiZ3JlZW4iLCAiYmx1ZSIsIm9yYW5nZSIpKQ0KICANCmZhY3Rvcl9yZXR1cm5zDQoNCg0KDQpgYGANCg0KIyMgOC4zIFN0cmF0ZWd5IENvbXBhcmlzb24gKDNmYWN0b3IsIDJmYWN0b3IsIDFmYWN0b3IpDQpgYGB7cn0NCg0Kcm93bmFtZXMoZGlmZmVyZW50U3RyYXRlZ2llcy5CUklDKSA8LSBjKCJCZW5jaG1hcmsiLCAiM0YiLCJWIiwgIkdMViIsIkdNT00iLCJMVk1PTSIsIkciLCJMViIsIk1PTSIpDQoNCg0KIyB0cmFuc2Zvcm1pbmcgdGhlIGluZGV4IG9mIHRoZSBkZiBpbnRvIGEgY29sdW1uDQpmYWN0b3JfcGxvdF9kZiA8LSBzZXREVChkaWZmZXJlbnRTdHJhdGVnaWVzLkJSSUMsIGtlZXAucm93bmFtZXMgPSBUUlVFKQ0KDQojIGRyb3BwaW5nIGFuIHVubmVjZXNzYXJ5IHJvdw0KZmFjdG9yX3Bsb3RfZGYgPC0gZmFjdG9yX3Bsb3RfZGZbLTMsXQ0KDQoNCiMgcmVuYW1pbmcgdGhlIDFzdCBjb2x1bW4NCmNvbG5hbWVzKGZhY3Rvcl9wbG90X2RmKVsxXSA8LSAgIlN0cmF0ZWdpZXMiDQoNCiMgc2F2aW5nIHRoZSBwbG90IGFzIGEganBlZyBmaWxlDQpqcGVnKCJyaXNrX3JldHVybl9mYWN0b3JzLmpwZWciLCB3aWR0aCA9IDQ4MCwgaGVpZ2h0ID0gNDgwKSAjIGhlaWdodCBhbmQgd2lkdGggY2FuIGJlIGNob3NlbiBhcyB5b3VyIHdpc2ggDQojIFpvb21pbmcgaW4gd2l0aCB4bGltL3lsaW0NCnBsb3RfY29tYmluYXRpb25zIDwtIGdncGxvdChkYXRhID0gZmFjdG9yX3Bsb3RfZGYsIGFlcyh4ID0gVm9sYXRpbGl0eSwgeSA9IFJldHVybiwgY29sb3I9IFN0cmF0ZWdpZXMpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC45LCBzaGFwZSA9IDIwKSArDQogIGdlb21fdGV4dChjb2xvcj0gImJsYWNrIiwgYWVzKGxhYmVsPVN0cmF0ZWdpZXMsbGFiZWw9IiIpLHNob3dfZ3VpZGU9RixoanVzdD0wLjYsdmp1c3Q9LTAuNSkgKw0KICBsYWJzKHk9ICJTdHJhdGVneSBSZXR1cm4gKGluICUgcC5hLikiLCB4ID0gIlZvbGF0aWxpdHkgKFNEIGluICUgcC5hLikiLCB0aXRsZSA9IlJpc2stcmV0dXJuIHNwYWNlIG9mIGZhY3RvciBjb21iaW5hdGlvbnMiKSArICMgeCBhbmQgeSBheGlzIGxhYmxlcyBhbmQgcGxvdCB0aXRsZSAgDQp0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpKSArDQogc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJTdHJhdGVnaWVzIiwgbGFiZWxzID0gYygiMyBGYWN0b3IiLCAiQmVuY2htYXJrIiwgIkdyb3d0aCIsICJHcm93dGhfTG93Vm9sIiwgIkdyb3d0aF9Nb21lbnR1bSIsIkxvd1ZvbCIsIkxvd1ZvbE1vbWVudHVtIiwiTW9tZW50dW0iKSkNCg0KDQpwbG90X2NvbWJpbmF0aW9ucw0KDQojIHNlY29uZCBwYXJ0IG9mIHRoZSBjb2RlIHRoYXQgY3JlYXRlcyB0aGUganBlZyBmaWxlIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkNCg0KYGBgDQojIyA4LjQgRXZvbHV0aW9uIG9mIE1hcmtldENhcCBXZWlnaHRzDQpgYGB7cn0NCiMgOC40LjEgU1RSQVRFR1kgLS0tLQ0KDQojIGNyZWF0ZSBhIGJhbGFuY2VkIHBhbmVsDQp5bSA8LSBzZXEoYXMueWVhcm1vbignMTk5Ni0wNy0wMScpLCBhcy55ZWFybW9uKCcyMDE4LTEwLTMxJyksIGJ5ID0gMC4wODMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMpDQp5bSA8LSBhcy5kYXRhLmZyYW1lKHltKQ0KY291bnRyeS54IDwtIGMoIkJSQSIsIkNITiIsIklORCIsIlJVUyIpDQpjb3VudHJ5LnggPC0gYXMuZGF0YS5mcmFtZShjb3VudHJ5LngpDQoNCiMgcHJlcGFyaW5nIGRhdGEgc2hlZXQNCnltQ291bnRyaWVzIDwtIGNyb3NzaW5nKHltLGNvdW50cnkueCkNCmV2b2x1dGlvbi52YWx1ZVdlaWdodHMgPC0gYWdncmVnYXRlKExNVi5VU0QgfiB5bSArIGNvdW50cnkueCwgZGF0YSA9IHN0cmF0ZWd5LCBGVU4gPSBzdW0pDQpiYWxhbmNlZF9zdHJhdGVneSA8LSBsZWZ0X2pvaW4oeCA9IHltQ291bnRyaWVzLCB5ID0gZXZvbHV0aW9uLnZhbHVlV2VpZ2h0cywgYnkgPSBjKCJ5bSIsICJjb3VudHJ5LngiKSkNCmV2b2x1dGlvbiA8LSBsZWZ0X2pvaW4oeCA9IGJhbGFuY2VkX3N0cmF0ZWd5LCB5ID0gc3RyYXRlZ3kudmFsdWVXZWlnaHRzLCBieSA9ICJ5bSIpDQpldm9sdXRpb24kTE1WLlVTRCA8LSBldm9sdXRpb24kTE1WLlVTRCAlPiUgcmVwbGFjZV9uYSgwKQ0KZXZvbHV0aW9uJFRvdGFsVmFsdWUgPC0gZXZvbHV0aW9uJFRvdGFsVmFsdWUgJT4lIHJlcGxhY2VfbmEoMCkNCmV2b2x1dGlvbiRDb3VudHJ5U2hhcmUgPC0gZXZvbHV0aW9uJExNVi5VU0QvZXZvbHV0aW9uJFRvdGFsVmFsdWUNCmV2b2x1dGlvbl93IDwtIGlubmVyX2pvaW4oeCA9IGV2b2x1dGlvbiwgeSA9IGV2b2x1dGlvbiwgYnkgPSAieW0iKQ0KZXZvbHV0aW9uX3UgPC0gaW5uZXJfam9pbih4ID0gZXZvbHV0aW9uLCB5ID0gZXZvbHV0aW9uX3csIGJ5ID0gInltIikNCmV2b2x1dGlvbl92IDwtIGlubmVyX2pvaW4oeCA9IGV2b2x1dGlvbiwgeSA9IGV2b2x1dGlvbl91LCBieSA9ICJ5bSIpDQpldm9sdXRpb24gPC0gZmlsdGVyKGV2b2x1dGlvbl92LGNvdW50cnkueC54LnggPT0gIkJSQSIgJiBjb3VudHJ5LngueSA9PSAiQ0hOIiAmIGNvdW50cnkueC54ID09ICJJTkQiICYgY291bnRyeS54LnkueSA9PSAiUlVTIikNCmNvbG5hbWVzKGV2b2x1dGlvbilbNV0gPC0gIkJSQSINCmNvbG5hbWVzKGV2b2x1dGlvbilbOV0gPC0gIkNITiINCmNvbG5hbWVzKGV2b2x1dGlvbilbMTNdIDwtICJJTkQiDQpjb2xuYW1lcyhldm9sdXRpb24pWzE3XSA8LSAiUlVTIg0KZXZvbHV0aW9uIDwtIHN1YnNldChldm9sdXRpb24sIHNlbGVjdCA9IGMoInltIiwiQlJBIiwiQ0hOIiwiSU5EIiwiUlVTIikpDQoNCiMgc2F2aW5nIHRoZSBwbG90IGFzIGEganBlZyBmaWxlDQpqcGVnKCJ3ZWlnaHRzX3N0cmF0ZWd5LmpwZyIsIHdpZHRoID0gNDgwLCBoZWlnaHQgPSA0ODApICMgaGVpZ2h0IGFuZCB3aWR0aCBjYW4gYmUgY2hvc2VuIGFzIHlvdXIgd2lzaA0KDQpvdmVydmlld19zdHJhdGVneSA8LSBnZ3Bsb3QoZGF0YSA9IGV2b2x1dGlvbiwgYWVzKHggPSB5bSkpICsgDQogIGdlb21fbGluZShhZXMoeSA9IEJSQSwgY29sb3VyPSJCUkEiKSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gQ0hOLCBjb2xvdXI9IkNITiIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBJTkQsIGNvbG91cj0iSU5EIikpICsgDQogIGdlb21fbGluZShhZXMoeSA9IFJVUywgY29sb3VyPSJSVVMiKSkgKyANCiAgbGFicyh5PSAiY291bnRyeSB3ZWlnaHQiLCB4ID0gInltIiwgdGl0bGUgPSJDb3VudHJ5IFdlaWdodHMgYnkgVmFsdWUgaW4gdGhlIDNGU3RyYXRlZ3kiKSArICMgeCBhbmQgeSBheGlzIGxhYmxlcyBhbmQgcGxvdCB0aXRsZQ0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iQ291bnRyeSB3ZWlnaHQiLCANCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJCUkEiLCAiQ0hOIiwgIklORCIsICJSVVMiKSwNCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQiLCAiZ3JlZW4iLCAiYmx1ZSIsIm9yYW5nZSIpKQ0Kb3ZlcnZpZXdfc3RyYXRlZ3kNCg0KIyBzZWNvbmQgcGFydCBvZiB0aGUgY29kZSB0aGF0IGNyZWF0ZXMgdGhlIGpwZWcgZmlsZSBvZiB0aGUgcGxvdA0KZGV2Lm9mZigpDQoNCiMgOC40LjIgQkVOQ0hNQVJLIC0tLS0NCg0KIyBjcmVhdGUgYSBiYWxhbmNlZCBwYW5lbA0KeW0gPC0gc2VxKGFzLnllYXJtb24oJzE5OTYtMDctMDEnKSwgYXMueWVhcm1vbignMjAxOC0xMC0zMScpLCBieSA9IDAuMDgzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzKQ0KeW0gPC0gYXMuZGF0YS5mcmFtZSh5bSkNCmNvdW50cnkueCA8LSBjKCJCUkEiLCJDSE4iLCJJTkQiLCJSVVMiKQ0KY291bnRyeS54IDwtIGFzLmRhdGEuZnJhbWUoY291bnRyeS54KQ0KDQojIHByZXBhcmluZyBkYXRhIHNoZWV0DQp5bUNvdW50cmllcyA8LSBjcm9zc2luZyh5bSxjb3VudHJ5LngpDQpldm9sdXRpb24udmFsdWVXZWlnaHRzIDwtIGFnZ3JlZ2F0ZShMTVYuVVNEIH4geW0gKyBjb3VudHJ5LngsIGRhdGEgPSBCUklDLmJlbmNobWFyaywgRlVOID0gc3VtKQ0KYmFsYW5jZWRfc3RyYXRlZ3kgPC0gbGVmdF9qb2luKHggPSB5bUNvdW50cmllcywgeSA9IGV2b2x1dGlvbi52YWx1ZVdlaWdodHMsIGJ5ID0gYygieW0iLCAiY291bnRyeS54IikpDQpldm9sdXRpb24gPC0gbGVmdF9qb2luKHggPSBiYWxhbmNlZF9zdHJhdGVneSwgeSA9IEJSSUMuYmVuY2htYXJrLnZhbHVlV2VpZ2h0cywgYnkgPSAieW0iKQ0KZXZvbHV0aW9uJExNVi5VU0QgPC0gZXZvbHV0aW9uJExNVi5VU0QgJT4lIHJlcGxhY2VfbmEoMCkNCmV2b2x1dGlvbiRUb3RhbFZhbHVlIDwtIGV2b2x1dGlvbiRUb3RhbFZhbHVlICU+JSByZXBsYWNlX25hKDApDQpldm9sdXRpb24kQ291bnRyeVNoYXJlIDwtIGV2b2x1dGlvbiRMTVYuVVNEL2V2b2x1dGlvbiRUb3RhbFZhbHVlDQpldm9sdXRpb25fdyA8LSBpbm5lcl9qb2luKHggPSBldm9sdXRpb24sIHkgPSBldm9sdXRpb24sIGJ5ID0gInltIikNCmV2b2x1dGlvbl91IDwtIGlubmVyX2pvaW4oeCA9IGV2b2x1dGlvbiwgeSA9IGV2b2x1dGlvbl93LCBieSA9ICJ5bSIpDQpldm9sdXRpb25fdiA8LSBpbm5lcl9qb2luKHggPSBldm9sdXRpb24sIHkgPSBldm9sdXRpb25fdSwgYnkgPSAieW0iKQ0KZXZvbHV0aW9uIDwtIGZpbHRlcihldm9sdXRpb25fdixjb3VudHJ5LngueC54ID09ICJCUkEiICYgY291bnRyeS54LnkgPT0gIkNITiIgJiBjb3VudHJ5LngueCA9PSAiSU5EIiAmIGNvdW50cnkueC55LnkgPT0gIlJVUyIpDQpjb2xuYW1lcyhldm9sdXRpb24pWzVdIDwtICJCUkEiDQpjb2xuYW1lcyhldm9sdXRpb24pWzldIDwtICJDSE4iDQpjb2xuYW1lcyhldm9sdXRpb24pWzEzXSA8LSAiSU5EIg0KY29sbmFtZXMoZXZvbHV0aW9uKVsxN10gPC0gIlJVUyINCmV2b2x1dGlvbiA8LSBzdWJzZXQoZXZvbHV0aW9uLCBzZWxlY3QgPSBjKCJ5bSIsIkJSQSIsIkNITiIsIklORCIsIlJVUyIpKQ0KDQojIHNhdmluZyB0aGUgcGxvdCBhcyBhIGpwZWcgZmlsZQ0KanBlZygid2VpZ2h0c19iZW5jaG1hcmsuanBnIiwgd2lkdGggPSA0ODAsIGhlaWdodCA9IDQ4MCkgIyBoZWlnaHQgYW5kIHdpZHRoIGNhbiBiZSBjaG9zZW4gYXMgeW91ciB3aXNoDQoNCm92ZXJ2aWV3X2JlbmNobWFyayA8LSBnZ3Bsb3QoZGF0YSA9IGV2b2x1dGlvbiwgYWVzKHggPSB5bSkpICsgDQogIGdlb21fbGluZShhZXMoeSA9IEJSQSwgY29sb3VyPSJCUkEiKSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gQ0hOLCBjb2xvdXI9IkNITiIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBJTkQsIGNvbG91cj0iSU5EIikpICsgDQogIGdlb21fbGluZShhZXMoeSA9IFJVUywgY29sb3VyPSJSVVMiKSkgKyANCiAgbGFicyh5PSAiY291bnRyeSB3ZWlnaHQiLCB4ID0gInltIiwgdGl0bGUgPSJDb3VudHJ5IFdlaWdodHMgYnkgVmFsdWUgaW4gdGhlIEJlbmNobWFyayIpICsgIyB4IGFuZCB5IGF4aXMgbGFibGVzIGFuZCBwbG90IHRpdGxlDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbChuYW1lPSJDb3VudHJ5IHdlaWdodCIsIA0KICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIkJSQSIsICJDSE4iLCAiSU5EIiwgIlJVUyIpLA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJlZCIsICJncmVlbiIsICJibHVlIiwib3JhbmdlIikpDQpvdmVydmlld19iZW5jaG1hcmsNCg0KIyBzZWNvbmQgcGFydCBvZiB0aGUgY29kZSB0aGF0IGNyZWF0ZXMgdGhlIGpwZWcgZmlsZSBvZiB0aGUgcGxvdA0KZGV2Lm9mZigpDQoNCiMgOC40LjMgR0RQIGV2b2x1dGlvbiBhcyBjb21wYXJpc29uIC0tLS0NCiMgbG9hZCBkYXRhIHNoZWV0IGZyb20gRnJlbmNoJ3Mgd2Vic2l0ZQ0KR0RQRGF0YSA8LSByZWFkX2NzdigiR0RQX3Jhd19kYXRhLmNzdiIsIA0KICAgICBza2lwID0gMykNCg0KIyByZW5hbWUgY29sdW1uDQpjb2xuYW1lcyhHRFBEYXRhKVsyXSA8LSAiQ291bnRyeUNvZGUiDQoNCiMgZmlsdGVyIG9uIEJSSUMgY291bnRyaWVzDQpHRFBEYXRhIDwtIEdEUERhdGEgJT4lIGZpbHRlcihDb3VudHJ5Q29kZSA9PSAiSU5EIiB8IENvdW50cnlDb2RlID09ICJDSE4iIHwgQ291bnRyeUNvZGUgPT0gIkJSQSIgfCBDb3VudHJ5Q29kZSA9PSAiUlVTIikNCg0KIyB0cmFuc3Bvc2UgZGF0YSBmcmFtZSBhbmQga2VlcCByb3cgbmFtZXMNCkdEUERhdGEgPC0gYXMuZGF0YS5mcmFtZSh0KEdEUERhdGEpKQ0Kc2V0RFQoR0RQRGF0YSwga2VlcC5yb3duYW1lcyA9IFRSVUUpW10NCg0KY29sbmFtZXMoR0RQRGF0YSlbMV0gPC0gInllYXIiDQpjb2xuYW1lcyhHRFBEYXRhKVsyXSA8LSAiQlJBIg0KY29sbmFtZXMoR0RQRGF0YSlbM10gPC0gIkNITiINCmNvbG5hbWVzKEdEUERhdGEpWzRdIDwtICJJTkQiDQpjb2xuYW1lcyhHRFBEYXRhKVs1XSA8LSAiUlVTIg0KDQojIHNob3J0aW5nIGRhdGEgZnJhbWUNCkdEUERhdGEgPC0gR0RQRGF0YSAlPiUgZmlsdGVyKHllYXIgPj0gMTk5NCAmIHllYXIgPCAyMDIwICkNCg0KY2xhc3MoR0RQRGF0YSRCUkEpDQoNCiMgY29udmVydCBmYWN0b3IgdHlwZSBvYmplY3RzIHRvIG51bWVyaWMgb2JqZWN0cw0KR0RQRGF0YSRCUkEgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoR0RQRGF0YSRCUkEpKQ0KR0RQRGF0YSRDSE4gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoR0RQRGF0YSRDSE4pKQ0KR0RQRGF0YSRJTkQgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoR0RQRGF0YSRJTkQpKQ0KR0RQRGF0YSRSVVMgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoR0RQRGF0YSRSVVMpKQ0KR0RQRGF0YSR5ZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKEdEUERhdGEkeWVhcikpDQoNCiMgZ2V0IHRoZSBzdW0gb2YgYWxsIEdEUHMNCkdEUERhdGEkU3VtT2ZHRFAgPC0gR0RQRGF0YSRCUkEgKyBHRFBEYXRhJENITiArIEdEUERhdGEkSU5EICsgR0RQRGF0YSRSVVMNCg0KIyBnZXQgJSBvZiB0b3RhbCBHRFAgcGVyIGNvdW50cnkNCkdEUERhdGEkQlJBX3cgPC0gR0RQRGF0YSRCUkEvR0RQRGF0YSRTdW1PZkdEUA0KR0RQRGF0YSRDSE5fdyA8LSBHRFBEYXRhJENITi9HRFBEYXRhJFN1bU9mR0RQDQpHRFBEYXRhJElORF93IDwtIEdEUERhdGEkSU5EL0dEUERhdGEkU3VtT2ZHRFANCkdEUERhdGEkUlVTX3cgPC0gR0RQRGF0YSRSVVMvR0RQRGF0YSRTdW1PZkdEUA0KDQojIHBsb3Qgb2YgR0RQIHdlaWdodHMgb3ZlciB0aW1lDQpvdmVydmlld19nZHAgPC0gZ2dwbG90KGRhdGEgPSBHRFBEYXRhLCBhZXMoeCA9IHllYXIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBCUkFfdywgY29sb3VyPSJCUkFfdyIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBDSE5fdywgY29sb3VyPSJDSE5fdyIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBJTkRfdywgY29sb3VyPSJJTkRfdyIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBSVVNfdywgY29sb3VyPSJSVVNfdyIpKSArIA0KICBsYWJzKHk9ICJjb3VudHJ5IHdlaWdodCIsIHggPSAiWWVhciIsIHRpdGxlID0iR0RQIHdlaWdodHMgYnkgY291bnRyeSIpICsgIyB4IGFuZCB5IGF4aXMgbGFibGVzIGFuZCBwbG90IHRpdGxlDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbChuYW1lPSJDb3VudHJ5IHdlaWdodCIsIA0KICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIkJSQV93IiwgIkNITl93IiwgIklORF93IiwgIlJVU193IiksDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmVkIiwgImdyZWVuIiwgImJsdWUiLCJvcmFuZ2UiKSkNCm92ZXJ2aWV3X2dkcA0KDQpgYGANCg0K